Resume powershell script after reboot [duplicate] - powershell

This question already has answers here:
Powershell - Reboot and Continue Script
(7 answers)
Closed 5 years ago.
I have a lot of articles about this subject but none of it is understandable.
My request is very simple. I have two part of my codes ; First of all Code 1 should be work and windows should be restarted. After reboot completion, Code 2 should be work. This process should be done silently at background. Powershell version is 4.0 ( Win 2012 R2 )
CODE 1 - This code is changing Computer Primary DNS Suffix.
$computerName = $env:computername
$DNSSuffix = "abc.com"
$oldDNSSuffix = (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\" -Name "NV Domain")."NV Domain"
#Update primary DNS Suffix for FQDN
Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\" -Name Domain -Value $DNSSuffix
Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\" -Name "NV Domain" -Value $DNSSuffix
#Update DNS Suffix Search List - Win8/2012 and above - if needed
#Set-DnsClientGlobalSetting -SuffixSearchList $oldDNSSuffix,$DNSSuffix
#Update AD's SPN records for machine if part of an AD domain
if ((gwmi win32_computersystem).partofdomain -eq $true) {
$searchAD = new-object System.DirectoryServices.DirectorySearcher
$searchAD.filter = "(&(objectCategory=computer)(cn=$($computerName)))"
$searchADItem = $searchAD.FindAll() | select -first 1
$adObj= [ADSI] $searchADItem.Path
$oldadObjSPN = $searchADItem.Properties.serviceprincipalname
$adObj.Put('serviceprincipalname',($oldadObjSPN -replace $oldDNSSuffix, $DNSSuffix))
$oldadObjDNS = $searchADItem.Properties.dnsHostName
$adObj.Put('dnsHostName',($oldadObjDNS -replace $oldDNSSuffix, $DNSSuffix))
$adObj.setinfo()
#$adObj.Get('serviceprincipalname')
#$adObj.Get('dnsHostName')
}
CODE 2 - Installing Terminal Services on this computer
Import-Module RemoteDesktop
Add-WindowsFeature -Name RDS-RD-Server -IncludeAllSubFeature
Add-WindowsFeature -Name RDS-Licensing -IncludeAllSubFeature

If you don’t want to roll your own with log files to check where it left off, you can look into powershell workflows which allows recovery after reboot. See https://technet.microsoft.com/en-us/library/jj574130(v=ws.11).aspx

powershell commands are very complicated, i decided to do this with batch file.
Resume batch script after computer restart

Related

Setting app pools to recycle at multiple specific times via powershell or appcmd does not display both times in GUI/IIS

I am attempting to set app pools to recycle at multiple times in the day in iis 8.5, I've tried using powershell and app command and when testing on a server that has no sites/applications in the pool it seems to work perfectly, however when trying to set using either method on a server that has sites in the app pools I'm seeing strange behavior, It seems to work however in the GUI of IIS if i look at the recycling settings of the app pool it only shows one of the times specified.
Powershell script initially tried using is:
function Set-ApplicationPoolRecycleTimes {
param (
[string]$ApplicationPoolName,
[string[]]$RestartTimes
)
Import-Module WebAdministration
Write-Output "Updating recycle times for $ApplicationPoolName"
# Delete all existing recycle times
Clear-ItemProperty IIS:\AppPools\$ApplicationPoolName -Name Recycling.periodicRestart.schedule
Clear-ItemProperty IIS:\AppPools\$ApplicationPoolName -Name Recycling.periodicRestart.time
foreach ($restartTime in $RestartTimes) {
Write-Output "Adding recycle at $restartTime"
# Set the application pool to restart at the time we want
New-ItemProperty -Path "IIS:\AppPools\$ApplicationPoolName" -Name Recycling.periodicRestart.schedule -Value #{value=$restartTime}
Set-ItemProperty -Path "IIS:\AppPools\$ApplicationPoolName" -Name Recycling.periodicRestart.time -Value "00:00:00"
} # End foreach restarttime
} # End function Set-ApplicationPoolRecycleTimes
$apppoolname1 = "app pool's name"
$restartat = #("1:45", "18:45")
Set-ApplicationPoolRecycleTimes -ApplicationPoolName $apppoolname1 -RestartTimes $restartat
Again this seems to work perfectly unless there are sites in the application pool. When sites exist it seems to work except that the gui only shows one of the times set:
however querying the value show's both times:
Import-Module WebAdministration
(Get-ItemProperty ('IIS:\AppPools\app pool name') -Name Recycling.periodicRestart.schedule.collection) | select value
value
-----
18:45:00
01:45:00
also attempted using appcmd but finding the same results, works perfectly on a server with no sites in the app pool, but when run against servers with sites, missing one of the times in the gui, querying shows both times. I have turned logging on for app pool recycles to confirm it's happening at both times but wondering if I'm just overlooking something obvious.
appcmd script:
CD C:\windows\System32\inetsrv
$V1 = "app pool name"
#clears any existing schedule
cmd.exe /c appcmd.exe set apppool /apppool.name: $V1 /-recycling.periodicRestart.schedule
#setting desired recycles
cmd.exe /c appcmd.exe set config -section:system.applicationHost/applicationPools /+"[name='$v1'].recycling.periodicRestart.schedule.[value='01:45:00']" /commit:apphost
cmd.exe /c appcmd.exe set config -section:system.applicationHost/applicationPools /+"[name='$v1'].recycling.periodicRestart.schedule.[value='18:45:00']" /commit:apphost
I tried your PowerShell script with the application pool which contains a site or without site.in both the condition your posted script is working.
you could try to use the below script:
function Set-ApplicationPoolRecycleTimes {
param (
[string]$ApplicationPoolName,
[string[]]$RestartTimes
)
Import-Module WebAdministration
Write-Output "Updating recycle times for $ApplicationPoolName"
# Delete all existing recycle times
Clear-ItemProperty IIS:\AppPools\$ApplicationPoolName -Name Recycling.periodicRestart.schedule
foreach ($restartTime in $RestartTimes) {
Write-Output "Adding recycle at $restartTime"
# Set the application pool to restart at the time we want
New-ItemProperty -Path "IIS:\AppPools\$ApplicationPoolName" -Name Recycling.periodicRestart.schedule -Value #{value=$restartTime}
} # End foreach restarttime
} # End function Set-ApplicationPoolRecycleTimes
$apppoolname = "abcsite"
$restartat = #("05:55", "12:55", "17:00")
Set-ApplicationPoolRecycleTimes -ApplicationPoolName $apppoolname -RestartTimes $restartat
or
appcmd.exe set config -section:system.applicationHost/applicationPools /+"[name='test1'].recycling.periodicRestart.schedule.[value='07:00:00']" /commit:apphost
appcmd.exe set config -section:system.applicationHost/applicationPools /+"[name='test1'].recycling.periodicRestart.schedule.[value='18:25:00']" /commit:apphost
or
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.applicationHost/applicationPools/add[#name='test1']/recycling/periodicRestart/schedule" -name "." -value #{value='07:00:00'}
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.applicationHost/applicationPools/add[#name='test1']/recycling/periodicRestart/schedule" -name "." -value #{value='18:25:00'}
The above scripts are tested with the IIS 10 (Windows 10) and IIS 8.5(windows server 2012r2)

Powershell Get-EventLog from computers.txt and save data

I have some problems getting EventLog and save data. I am able to get my EventLogs but not logs from network computers.
Here is the code I am running:
$logFileName = "Application"
$path = $MyInvocation.MyCommand.Path +"\Output\"
$path = $PSScriptRoot+"\Output\"
new-item $path -ItemType directory
$array = ("System", "Security")
$file = $PSScriptRoot +"\computers.txt"
$users = ForEach ($machine in $(Get-Content $file)) {
$pathMachine = $path+$machine
new-item $pathMachine -ItemType directory
ForEach ($logFileName in $array){
# do not edit
$logFileName
$exportFileName = (get-date -f yyyyMMdd) + "_" + $logFileName + ".evt"
$logFile = Get-WmiObject Win32_NTEventlogFile -ComputerName $machine | Where-Object {$_.logfilename -eq $logFileName}
$logFile
$exportFileName
$pathMachine
$temp = $pathMachine + "\"+ $exportFileName
$temp
$fff = $logFile.BackupEventLog($temp)
}
}
This could e considered a duplicate of this.
Reading event log remotely with Get-EventLog in Powershell
# swapped from this command
get-eventlog -LogName System -computername <ServerName>
# to this
invoke-command {get-eventlog -LogName System} -ComputerName <ServerName>
Don't struggle with writing this from scratch. Well, unless it's a learning exercise. There are pre-built script for you to leverage as is and or tweak as needed.
Running commands on Remote host require using the Invoke cmdlet, and or an established PSRemoting session to that host.
Get Remote Event Logs With Powershell
Gather the remote event log information for one or more systems using wmi, alternate credentials, and multiple runspaces. Function supports custom timeout parameters in case of wmi problems and returns Event Log information for the specified number of past hours.
Download: Get-RemoteEventLogs.ps1
The script is too long (it's 100+ lines) to post here, but here in the Synopsis of it.
Function Get-RemoteEventLogs
{
<#
.SYNOPSIS
Retrieves event logs via WMI in multiple runspaces.
.DESCRIPTION
Retrieves event logs via WMI and, if needed, alternate credentials. This function utilizes multiple runspaces.
.PARAMETER ComputerName
Specifies the target computer or comptuers for data query.
.PARAMETER Hours
Gather event logs from the last number of hourse specified here.
.PARAMETER ThrottleLimit
Specifies the maximum number of systems to inventory simultaneously
.PARAMETER Timeout
Specifies the maximum time in second command can run in background before terminating this thread.
.PARAMETER ShowProgress
Show progress bar information
.EXAMPLE
PS > (Get-RemoteEventLogs).EventLogs
Description
-----------
Lists all of the event logs found on the localhost in the last 24 hours.
.NOTES
Author: Zachary Loeber
Site: http://www.the-little-things.net/
Requires: Powershell 2.0
Version History
1.0.0 - 08/28/2013
- Initial release
#>
Or this one.
PowerShell To Get Event Log of local or Remote Computers in .csv file
This script is handy when you want to extract the eventlog from remote or local machine. It has multiple filters which will help to filter the data. You can filter by logname,event type, source etc. This also have facility to get the data based on date range. You can change th
Download : eventLogFromRemoteSystem.ps1
Again, too big to post here because the length is like the other one.
I am working on some assumptions but maybe this will help.
When I Ran your Code I got
Get-Content : Cannot find path 'C:\computers.txt' because it does not exist.
I had to make the C:\computers.txt file, then I ran your code again and got this error.
Get-Content : Cannot find path 'C:\Output\computers.txt' because it does not exist.
I made that file in that location, then I ran your code again and I got the event log file. Maybe try creating these two missing files with a command like
Get-WmiObject Win32_NTEventlogFile -ComputerName $machine
mkdir C:\Output\$machine
$env:computername | Out-File -FilePath c:\Output\Computers.txt
You may also want to setup a Network share and output to that location so you can access the event logs from a single computer. Once the share is setup and the permissions just drop the unc path in.

Powershell Suppress Certificate Notification

I am writing a script to connect from a Windows 10 Client to a Terminal Server with the RDP-Protocoll.
The thought behind is: On these ThinClients we have about 20 RDP-Files. With about 10 of them, the password needs to be safed.
So it is quite a lot of work if you always have to save the password on every new ThinClient.
But I thought I could solve this problem with a powershell script. I just have to open the connection 1 time successfully and save the credentials and further on the credentials are saved.
I will show my code first:
$Server = "xx.yy.zz.xx"
$User = "DOMAIN\User"
$password = "password"
cmdkey /generic:"$Server" /user:"$User" /pass:"$password"
mstsc /v:"$Server"
This works so far.
But I always get the this Notification:
This is a Symbol-Picture from the Internet, as my Notification is in German. It is exactly the same, just easier to understand.
Even if I install the certificate, the notification keeps popping up.
How can I check the field with Powershell, where it says Don't ask me again for connections to this computer?
Ok i found a solution!
There is a registry-Key generated when you Tick "Dont ask me again..."
Now i just added the necessary Registry Keys with my Powershell Script..
function Test-RegistryValue {
param (
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]$Path,
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]$Value
)
try{
Get-ItemProperty -Path $Path | Select-Object -ExpandProperty $Value -ErrorAction Stop | Out-Null
return $true
}
catch{
return $false
}
}
#Certificate warning turn off
$exists = Test-RegistryValue -Path 'HKCU:\Software\Microsoft\Terminal Server Client' -Value 'AuthenticationLevelOverride'
if($exists -eq $False){
reg add "HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client" /v "AuthenticationLevelOverride" /t "REG_DWORD" /d 0 /f
}
Like this it works without this certificate notification!

net use * /delete /y doesn't resolve error "New-PSDrive : Multiple connections to a server ...."

This New-PSDrive command
New-PSDrive -Name Z -PSProvider FileSystem -Root \\$j\share -Credential $credentials -ErrorAction Stop
Causes the error
New-PSDrive : Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the
server or shared resource and try again
I have tried disconnecting all drives first, then creating new drive,
net use * /delete /y
New-PSDrive -Name Z -PSProvider FileSystem -Root \\$j\share -Credential $credentials -ErrorAction Stop
I get the output
You have these remote connections:
\\TSCLIENT\C
\\TSCLIENT\D
\\TSCLIENT\E
\\TSCLIENT\I
\\TSCLIENT\J
\\TSCLIENT\K
\\TSCLIENT\L
\\TSCLIENT\R
\\TSCLIENT\T
Continuing will cancel the connections.
The command completed successfully.
New-PSDrive : Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the
server or shared resource and try again
I also tried removing the Z drive first
Remove-PSDrive -name Z
New-PSDrive -Name Z -PSProvider FileSystem -Root \\$j\share -Credential $credentials -ErrorAction Stop
And get error
Remove-PSDrive : Cannot find drive. A drive with the name 'Z' does not exist.
...
New-PSDrive : Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the
server or shared resource and try again
How to fix?
UPDATE
I even rebooted the machine and changed the drive name, but I still get the same error of "New-PSDrive: Multiple connections ......"
UPDATE 2
I have also tried using IP address instead of computer name, but that doesn't work either, http://support.microsoft.com/kb/938120
I found workaround to this problem that seem to always work. You need to change the computer name, but since this will also stop working eventually just as with server name and IP, you need the option to specify arbitrary number of new computer names resolving to the same computer.
The obvious choice is hosts file. You can add any number of aliases to the IP to it. Afterwards, use the alias that isn't already blocked.
==== EDIT ===
Here is the handy function:
<# Use unique hostname for this script by altering hosts table to handle situation with multiple different scripts
using this share with different creds which leads to following Windows error:
Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed.
Disconnect all previous connections to the server or shared resource and try again
#require -RunAsAdministrator
#require -module PsHosts
https://stackoverflow.com/a/29059100/82660
#>
function Set-UncHostnameAlias($UncPath) {
$remote_hostname = $UncPath -split '\\' | ? {$_} | select -First 1
$remote_alias = (Split-Path -Leaf $MyInvocation.ScriptName) -replace '.ps1$'
$hostEntry = Get-HostEntry $remote_alias* -ea 0 | ? { $_.Comment -eq $remote_hostname } | select -First 1
if (!$hostEntry) {
$remote_alias += (Get-HostEntry $remote_alias*).Count + 1
Write-Verbose "Adding alias $remote_alias => $remote_hostname"
$remote_ip = Test-Connection -ComputerName $remote_hostname -Count 1 | % IPV4Address | % IPAddressToString
Add-HostEntry -Name $remote_alias -Address $remote_ip -Force -Comment $remote_hostname | Out-Null
} else {
$remote_alias = $hostEntry.Name
Write-Verbose "Using $remote_hostname alias: $remote_alias"
}
$UncPath.Replace("\\$remote_hostname", "\\$remote_alias")
}
Do this on the start of the script:
$PathAlias = Set-UncHostnameAlias $Path
and used aliased path afterwards with the New-PSDrive. This works always, even if some other scripts on the same system use different credentials for the same server.
I was having the same issue with local scripts and found this to be a simple solution. The Get-CimInstance returns all of the mapped network connections, then just pass that to the net use /delete /y command.
$shareDrives = Get-CimInstance -ClassName Win32_NetworkConnection
if ($shareDrives -ne $null)
{
foreach ($shareDrive in $shareDrives)
{
Write-Host "`nRemoving mapped drive $($shareDrive.LocalName)"
net use $shareDrive.LocalName /delete /y
}
}
else
{
Write-Host "`nNo mapped drives to remove!"
}
Using the FQND worked for me..
How to find out FQDN??
ping -a -n 1
Pinging [This is the FQND!!!!] [192.168.0.1] with 32 bytes of
Reply from 192.168.0.1: bytes=32 time=1ms TTL=128
You need to use the FQDN instead of the NetBios name.
My script needs to be client computer independent since other members of my team might run it. This works for me. Not sure if the "Write-Host" is needed but it also doesn't get in the way. Also, there is some sort of error that doesn't affect using the drive again if it already exists.
if (Get-PSDrive DLL_NEW_TEMP -ErrorAction SilentlyContinue){Write-Host "DLL_NEW_TEMP Drive exists"}
else{
New-PSDrive -Name DLL_NEW_TEMP -PSProvider FileSystem -Root \\WTDHSxxxL32\d$\ServerDLLDev\New_DLL_temp_location -Credential $credential
}
if (Get-PSDrive DLL_WORKING -ErrorAction SilentlyContinue){Write-Host "DLL_WORKING Drive exists"}
else{
New-PSDrive -Name DLL_WORKING -PSProvider FileSystem -Root \\WTDHSxxx32\d$\ServerDLLDev -Credential $credential
}
The below information I found on here
This error message means that you already have a connection to that UNC path, whether it's defined on your computer or not. Windows only allows you to connect to a particular UNC path with one username, regardless of the number of connections to that UNC. If you use the same username for all connections to a UNC from your computer then you shouldn't run into this error.
My issue and its solution: I was connected to the shared drive and it was open in my session with my credentials and at the same I've tried to run New-PSDrive with other credential. After closing my session with the shared drive the command worked like a pro.
If you have to use a different username to connect, then one workaround is to connect to the UNC using an IP address or other alias so that it looks like it's a different path. This is also the workaround recommended by Microsoft:

Powershell - Copying File to Remote Host and Executing Install exe using WMI

EDITED: Here is my code now. The install file does copy to the remote host. However, the WMI portion does not install the .exe file, and no errors are returned. Perhaps this is a syntax error with WMI? Is there a way to just run the installer silently with PsExec? Thanks again for all the help sorry for the confusion:
#declare params
param (
[string]$finalCountdownPath = "",
[string]$slashes = "\\",
[string]$pathOnRemoteHost = "c:\temp\",
[string]$targetJavaComputer = "",
[string]$compname = "",
[string]$tempPathTarget = "\C$\temp\"
)
# user enters target host/computer
$targetJavaComputer = Read-Host "Enter the name of the computer on which you wish to install Java:"
[string]$compname = $slashes + $targetJavaComputer
[string]$finalCountdownPath = $compname + $tempPathTarget
#[string]$tempPathTarget2 =
#[string]$finalCountdownPath2 = $compname + $
# say copy install media to remote host
echo "Copying install file and running installer silently please wait..."
# create temp dir if does not exist, if exist copy install media
# if does not exist create dir, copy dummy file, copy install media
# either case will execute install of .exe via WMII
#[string]$finalCountdownPath = $compname + $tempPathTarget;
if ((Test-Path -Path $finalCountdownPath) )
{
copy c:\hdatools\java\jre-7u60-windows-i586.exe $finalCountdownPath
([WMICLASS]"\\$targetJavaComputer\ROOT\CIMV2:win32_process").Create("cmd.exe /c c:\temp\java\jre-7u60-windows-i586.exe /s /v`" /qn")
}
else {
New-Item -Path $finalCountdownPath -type directory -Force
copy c:\hdatools\dummy.txt $finalCountdownPath
copy "c:\hdatools\java\jre-7u60-windows-i586.exe" $finalCountdownPath
([WMICLASS]"\\$targetJavaComputer\ROOT\CIMV2:win32_process").Create("cmd.exe /c c:\temp\java\jre-7u60-windows-i586.exe /s /v`" /qn")
}
I was trying to get $Job = Invoke-Command -Session $Session -Scriptblock $Script to allow me to copy files on a different server, because I needed to off load it from the server it was running from. I was using the PowerShell Copy-Item to do it. But the running PowerShell script waits until the file is done copying to return.
I want it to take as little resources as possible on the server that the powershell is running to spawn off the process on another server to copy the file. I tried to user various other schemes out there, but they didn't work or the way I needed them to work. (Seemed kind of kludgey or too complex to me.) Maybe some of them could have worked? But I found a solution that I like that works best for me, which is pretty easy. (Except for some of the back end configuration that may be needed if it is is not already setup.)
Background:
I am running a SQLServer Job which invokes Powershell to run a script which backups databases, copies backup files, and deletes older backup files, with parameters passed into it. Our server is configured to allow PowerShell to run and under the pre-setup User account with SQL Server Admin and dbo privileges in an Active Directory account to allow it to see various places on our Network as well.
But we don't want it to take the resources away from the main server. The PowerShell script that was to be run would backup the database Log file and then use the another server to asynchronously copy the file itself and not make the SQL Server Job/PowerShell wait for it. We wanted it to happen right after the backup.
Here is my new way, using WMI, using Windows Integrate Security:
$ComputerName = "kithhelpdesk"
([Wmiclass]'Win32_Process').GetMethodParameters('Create')
Invoke-WmiMethod -ComputerName RemoteServerToRunOn -Path win32_process -Name create -ArgumentList 'powershell.exe -Command "Copy-Item -Path \\YourShareSource\SQLBackup\YourDatabase_2018-08-07_11-45.log.bak -Destination \\YourShareDestination\YourDatabase_2018-08-07_11-45.log.bak"'
Here is my new way using passed in Credentials, and building arg list variable:
$Username = "YouDomain\YourDomainUser"
$Password = "P#ssw0rd27"
$ComputerName = "RemoteServerToRunOn"
$FromFile = "\\YourShareSource\SQLBackup\YourDatabase_2018-08-07_11-45.log.bak"
$ToFile = "\\YourShareDestination\SQLBackup\YourDatabase_2018-08-07_11-45.log.bak"
$ArgumentList = 'powershell.exe -Command "Copy-Item -Path ' + $FromFile + ' -Destination ' + $ToFile + '"'
$SecurePassWord = ConvertTo-SecureString -AsPlainText $Password -Force
$Cred = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $Username, $SecurePassWord
([Wmiclass]'Win32_Process').GetMethodParameters('Create')
Invoke-WmiMethod -ComputerName $ComputerName -Path win32_process -Name create -ArgumentList $ArgumentList -Credential $Cred
We think that this above one is the preferred one to use.
You can also run a specific powershell that will do what you want it to do (even passing in parameters to it):
Invoke-WmiMethod -ComputerName RemoteServerToRunOn -Path win32_process -Name create -ArgumentList 'powershell.exe -file "C:\PS\Test1.ps1"'
This example could be changed to pass in parameters to the Test1.ps1 PowerShell script to make it more flexible and reusable. And you may also want to pass in a Credential like we used in a previous example above.
Help configuring WMI:
I got the main gist of this working from: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/invoke-wmimethod?view=powershell-5.1
But it may have also needed WMI configuration using:
https://helpcenter.gsx.com/hc/en-us/articles/202447926-How-to-Configure-Windows-Remote-PowerShell-Access-for-Non-Privileged-User-Accounts?flash_digest=bec1f6a29327161f08e1f2db77e64856b433cb5a
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/enable-psremoting?view=powershell-5.1
Powershell New-PSSession Access Denied - Administrator Account
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/invoke-wmimethod?view=powershell-5.1 (I used to get how to call Invoke-WmiMethod).
https://learn.microsoft.com/en-us/powershell/scripting/core-powershell/console/powershell.exe-command-line-help?view=powershell-6 (I used to get syntax of command line)
I didn't use this one, but could have: How to execute a command in a remote computer?
I don't know for sure if all of the steps in the web articles above are needed, I suspect not. But I thought I was going to be using the Invoke-Command PowerShell statement to copy the files on a remote server, but left my changes from the articles above that I did intact mostly I believe.
You will need a dedicated User setup in Active Directory, and to configure the user accounts that SQL Server and SQL Server Agent are running under to give the main calling PowerShell the privileges needed to access the network and other things to, and can be used to run the PowerShell on the remote server as well. And you may need to configure SQLServer to allow SQL Server Jobs or Stored Procedures to be able to call PowerShell scripts like I did. But this is outside the scope of this post. You Google other places on the internet to show you how to do that.