For some circumstances, you may want to move data and log files for a database to a different location.
Usually, this operation has to be made offline. But with an Availability Group (AG) environment, it is possible to choose an approach which is slightly transparent.

If you have a lot of databases to process, you may want to automate this operation: PowerShell is quite convenient for that.
In this blog, I will present you how I did using dbatools module.

In the following script, I took the primary as reference for my restore: this is just as an example.
Of course, you can customize the target folders based on your needs.

# IMPORTANT: dbatools needs to be installed on the server where running this script

# Configure the following parameters
$Primary = '<MyPrimary>';
$Secondary = '<MySecondary>';
$Database = '<MyDatabase>';
$AvailabilityGroup = '<MyAG>';

$SharedBackup = '<MyShare>';


Try
{
    Write-Output "Importing module dbatools";
    Import-Module -Name dbatools;
    Write-Output '...ok';
    
    $DatabaseFilesQuery =  "
    SELECT SERVERPROPERTY('ServerName') as Server_Instance,
    '$($Database)' as Database_Name,
    name as Logical_Name,
    physical_name as Physical_Name, 
    type_desc as Type_Description,
    size/128 as Size_MB
    FROM sys.master_files 
    WHERE database_id = DB_ID('$($Database)')";

    Write-Output "Retrieving information about current database files";
    $dbFiles = Invoke-DbaQuery -SqlInstance $Secondary -Database 'master' -Query $DatabaseFilesQuery -EnableException;

    $dbFiles | Format-Table Server_Instance, Database_Name, Physical_Name, Type_Description, Size_MB;
    Write-Output '...ok';

    # Retrieve locations from primary
    Write-Output "Retrieving information about new database folders";
    
    $Files = Get-DbaDbFile -SqlInstance $Primary -Database $Database;

    # Locate all data files based on primary data file
    $NewDataFolder = Split-Path (($Files | Where-Object { ($_.Type -eq 0) -and ($_.ID -eq 1) -and ($_.FileGroupName -eq 'PRIMARY')}).PhysicalName);
	
	# Assume there is only one log file
    $NewLogFolder = Split-Path (($Files | Where-Object { ($_.Type -eq 1) -and ($_.ID -eq 2)}).PhysicalName)
    Write-Output '...ok';
    

	$title   = 'Removing secondary database from old folers'
	$msg     = "Do you want to Move database file(s) to  $($NewDataFolder) and to $($NewLogFolder) on Secondary $($Secondary)?"
	$options = '&Yes', '&No'
	$default = 1  # 0=Yes, 1=No

	$Continue = $False;
	
	do {
		$response = $Host.UI.PromptForChoice($title, $msg, $options, $default)
		if ($response -eq 0) {
			$Continue = $True;
			$response = 1;
		}
	} until ($response -eq 1)
	
	If (-not $Continue){
		Write-Warning "Aborted by user...";
		Return;
    }


    # Create subfolder to database
    Write-Output "Creating new database folders";
    $CreateSubFoldersQuery = "
    EXECUTE [master].dbo.xp_create_subdir '$($NewDataFolder)';
    EXECUTE [master].dbo.xp_create_subdir '$($NewLogFolder)';
    "
    $Null = Invoke-DbaQuery -SqlInstance $Secondary -Database 'master' -Query $CreateSubFoldersQuery -EnableException;
    Write-Output '...ok';

    # Remove database from AG on secondary
    Write-Output "Removing database $($Database) from Secondary $($Secondary)";
    $RemoveDBSecondaryQuery = "
    ALTER DATABASE [$($Database)] SET HADR OFF;
    ";
    $Null = Invoke-DbaQuery -SqlInstance $Secondary -Database 'master' -Query $RemoveDBSecondaryQuery -EnableException;
    Write-Output '...ok';

    # Backup Source database - Copy Only option is configurable with this command
    Write-Output "Performing full backup of database $($Database) to Shared Backup $($SharedBackup)";
    $FullBackups = Backup-DbaDatabase -SqlInstance $Primary -Database $Database -Path $SharedBackup -Type Full -FileCount 4;
    Write-Output '...ok';

    Write-Output "Performing log backup of database $($Database) to Shared Backup $($SharedBackup)";
    $LogBackup = Backup-DbaDatabase -SqlInstance $Primary -Database $Database -Path $SharedBackup -Type Log;
    Write-Output '...ok';

    # Restore to secondary with moving files
    Write-Output "Restoring FULL backup for database $($Database) on Secondary $($Secondary)";
    Restore-DbaDatabase -Path $FullBackups -EnableException -SqlInstance $Secondary -WithReplace -NoRecovery -DestinationDataDirectory "$($NewDataFolder)" -DestinationLogDirectory "$($NewLogFolder)";
    Write-Output '...ok';

    Write-Output "Restoring LOG backup for database $($Database) on Secondary $($Secondary)";
    Restore-DbaDatabase -Path $LogBackup -EnableException -SqlInstance $Secondary -NoRecovery -Continue;
    Write-Output '...ok';

    # Add database AG to secondary
    Write-Output "Adding database $($Database) on Secondary $($Secondary)";
    $AddDBSecondaryQuery = "
    ALTER DATABASE [$($Database)] SET HADR AVAILABILITY GROUP = $($AvailabilityGroup);
    ";
    $Null = Invoke-DbaQuery -SqlInstance $Secondary -Database 'master' -Query $AddDBSecondaryQuery -EnableException;
    Write-Output '...ok';

    # Clean up backup files
    Write-Output "Cleaning full backup files";
    Remove-Item -Path $FullBackups.FullName;
    Write-Output '...ok';

}
Catch
{
	Write-Error $_.Exception.toString();
}

The script includes a TRY/CATCH block to stop at any unattended error: it offers a safe way to avoid any side effects.

Enjoy automation!