Powershell Invoke-Command Operations Error - powershell

I'm stumped by this issue.
I've written a powershell script which I'm trying to use to import a GPO across multiple domains and then link it with new-gplink. I've made sure all servers have GP Powershell module installed and it's been working pretty well so far, however the issue I'm running into is that on some servers my command works fine on others I get the error, on the last step I'm getting an operations error one of my invoke-commands. Other commands work on the same server with invoke-command such as get-service, or even the import-GPO command that I use.
The error in question:
An operations error occurred. (Exception from HRESULT: 0x80072020)
+ CategoryInfo : NotSpecified: (:) [New-GPLink], COMException
+ FullyQualifiedErrorId : System.Runtime.InteropServices.COMException,Microsoft.GroupPolicy.Commands.NewGPLinkCommand
+ PSComputerName : 10.0.0.10
The command:
Invoke-Command -ComputerName $serverip -scriptblock {New-GPLink -Name "GPO" -Target $args[0]} -ArgumentList $oupath -credential $cred
I've tried every version of this command I can imagine. without [0], without argument list, just using the server ip and replacing the target with the OU path and I still get the same error, such as below.
Invoke-Command -ComputerName $serverip -scriptblock {New-GPLink -Name "GPOName" -Target ou=users,ou=site,ou=domain,dc=server,dc=com} -ArgumentList $oupath -credential $cred
The way I have it working is a .csv with the server info, it gets imported into a foreach loop and then fed into the script. I have it grab credentials and feed through. I know everything else is working because my invoke-command to import the GPO worked, all servers I ran to successfully imported the GPO. I also know my OU paths are correct because I use them locally with another script to place computers where I want them. a sample line in the csv would be something like
servername, 10.0.0.10, domain.com, OU=user,OU=site,DC=domain,DC=com
I've also ran the command locally and get a similar error:
PS> New-GPLink -Name "GPO" -Target "ou=users,ou=Site,dc=domain,dc=com"
New-GPLink : A referral was returned from the server.
At line:1 char:1
+ New-GPLink -Name "GPO" -Target "ou=users,ou=site,dc=domain,d ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [New-GPLink], DirectoryServicesCOMException
+ FullyQualifiedErrorId : System.DirectoryServices.DirectoryServicesCOMException,Microsoft.GroupPolicy.Commands.NewGPLinkCommand
Please let me know if there are additional question or if you need additional info. I'm completely stumped by this issue and I appreciate any help you can provide. Thanks in advance.
Edit: All of my servers are at least 2008 R2 and are using powershell version 3,0,1,1
PS> $psversiontable.psversion
Major Minor Build Revision
----- ----- ----- --------
3 0 -1 -1

You need to specify a the domain in which your trying to apply the GPO, as well as a Domain Controller from the domain in question with the -Domain and -Server parameters respectively:
$OU = "ou=users,ou=Site,dc=domain,dc=com"
New-GPLink -Name "GPO" -Target $OU -Server "domain.com" -Domain "domain.com"
Instead of just using the domain name though, the proper way to do this, is to actually locate a Domain Controller, like so:
$DC = Get-ADDomainController -Discover -DomainName "domain.com" |Select -ExpandProperty HostName
New-GPLink -Name "GPO" -Target $OU -Server $DC -Domain "domain.tld"
Or in an environment where Get-ADDomainController is not available, you can emulate the DCLocator (aka. the underlying high-availability design of AD DS) behavior with .NET:
$DomainFqdn = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$dctx = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext -ArgumentList "Domain",$DomainFqdn
$DomainController = $[System.DirectoryServices.ActiveDirectory.DomainController]::FindOne($dctx)
New-GPLink -Name "GPO" -Target $OU -Server $DomainController.Name -Domain $DomainFqdn

Related

How to Install Windows Updates on Remote Computer with PowerShell

I'm trying to install Windows Updates on a Remote Computer with this command:
$InstallSplat = #{
AcceptAll = $true
SendReport = $true
IgnoreReboot = if ($Reboot) { $false } else { $true }
PSWUSettings = #{
SmtpServer = "my mail server"
From = "myfrom <myfrom#myfrom.com>"
To = "myto <myto#myto.com>"
Port = 25
}
}
Invoke-Command -ComputerName $_ -Credential $cred -AsJob -ArgumentList $InstallSplat -ScriptBlock {
param([hashtable]$InstallSplat)
Import-Module PSWindowsUpdate
Install-WindowsUpdate #InstallSplat
$Error | out-file C:\install\installwinupdate.log -Append
}
I pass a credential Object with domain admin privileges in $cred but I still always get this error
Install-WindowsUpdate : Access denied (Ausnahme von HRESULT: 0x80070005 (E_ACCESSDENIED)) In Zeile:4 Zeichen:25
+ Install-WindowsUpdate #InstallSplat
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WindowsUpdate], UnauthorizedAccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,PSWindowsUpdate.GetWindowsUpdate
The Command Install-WindowsUpdate itself does not have a credential parameter I could use. The Command needs to run in an elevated PowerShell, but I use an elevated PowerShell when starting this command on my Computer.
I Also tried creating a New-PSSession with my $cred and run Invoke-Command -Session $session instead of Invoke-Command -ComputerName $_ with the same result.
Does anybody know what's happening here? Why do I get Access denied?
It can't have anything to do with passing the $InstallSplat because the same thing happens if I don't pass any parameter at all and write the parameters and their Values directly at the command instead of splatting.
The Problem was, that you can't Download or Install Updates on a machine from another remote machine. Here's a list what you can or can't do remotely when it comes to Windows Updates
The solution is, to create a scheduled task on each server you want to install updates from a remote script, and start that task.
luckily, when you use the PSWindowsUpdate module, you don't have to do that yourself, you can just use Invoke-WUJob (formerly Invoke-WUInstall) which does the trick for you.
I used it like so ($ServerData.Value contains a list of my Servers) and it works like a charm. It creates a scheduled task on each server, and runs them immediately, if you add the -RunNow Parameter.
invoke-WUJob -ComputerName $ServerData.Value -Script { Import-Module PSWindowsUpdate ; Install-WindowsUpdate -AcceptAll -SendReport -IgnoreReboot -PSWUSettings #{From='xy';Port=25;SmtpServer='xy';To='xy'} | Out-File C:\install\PSWindowsUpdateLog.txt -Append} -Confirm:$false -verbose -RunNow
Note that what you specify as a script block in -Script will be pasted to -Command " <here> " in your scheduled task, so you should work with ' inside -Script.

PSCredential variable stops working for WinRM function after being passed to get-winevent

I am seeing WinRM Client errors when reusing a Credential object, but only if I'm using it on Get-WinEvent, before I used it on Get-WindowsFeature.
If I replace the Get-WindowsFeature with an Invoke-Command calling Get-WindowsFeature against the server and using the same credentials object then things work as expected, but that causes other issues with different parts of my script, and I'd rather understand why it's not working.
I've stripped things down to the bare minimum to demonstrate the error and got to this.
$Cred = Get-Credential
$Name = "server01"
Get-WindowsFeature -ComputerName $Name -Credential $Cred
Get-winEvent -ComputerName $Name -Credential $Cred -MaxEvents 1
Get-WindowsFeature -ComputerName $Name -Credential $Cred
Expected Results
List of Windows features and their status on server01
The most recent event log entry on server01
List of Windows features and their status of server01
Actual Results
List of Windows features and their status on server01
The most recent event log entry on server01
Get-WindowsFeature : The WinRM client cannot process the request. Requests must include user name and password when Basic or Digest authentication mechanism is used. Add the
user name and password or change the authentication mechanism and try the request again.
At line:1 char:1
+ Get-WindowsFeature -ComputerName $Name -Credential $Cred
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WindowsFeature], CimException
+ FullyQualifiedErrorId : Microsoft.Management.Infrastructure.CimException,Microsoft.Windows.ServerManager.Commands.GetWindowsFeatureCommand
why not try this instead
$Cred = Get-Credential
$Name = "server01"
invoke-command -ComputerName $Name -Credential $Cred -ScriptBlock {
Get-WindowsFeature
Get-winEvent -MaxEvents 1
Get-WindowsFeature
}

find service account on remote hosts

Could you please advise how to find all servers where a specific service account is being used to start Windows services?
I am trying this in PowerShell with these code:
Clear-Host
$address = Get-Content '.\asg connections.csv'
$serviceName = "startname='NT AUTHORITY\\LocalService'"
gwmi Win32_Service -Filter $serviceName -Computer $address
Above piece of code works for "localhost", but gives below error for the remote hosts:
gwmi : Access is denied. (Exception from HRESULT: 0x80070005
(E_ACCESSDENIED))
At F:\Temp\powershell\play.ps1:30 char:1
+ gwmi win32_service -filter $serviceName -computer $address
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WmiObject], UnauthorizedAccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
When you use PowerShell remoting you implicitly trying to use the credentials your current Windows session is logged into your machine with on the target machines.
It looks like you do not have any rights with your current set of credentials on those machines.
Are the target machines joined into the same domain as your current user credentials?
If you have a set of working credentials you can log onto those machines with, you can add it in your command with:
Clear-Host
#Promts you for the username and password you wish to save to a credential object
$Cred = Get-Credential
$address = Get-Content '.\asg connections.csv'
$serviceName = "startname='NT AUTHORITY\\LocalService'"
gwmi Win32_Service -Filter $serviceName -Computer $address -Credential $Cred
If the script needs to run automated there are a few different ways to save credential passwords either into an encrypted textfile that can only be decrypted by the user account that encrypted it, or using the build in Windows Credential Vault.

Enter-PSSession to custom endpoint: Cmdlet not recognized

I am trying to setup an Endpoint-Server in my company and am struggling to connect to it. For testing I put a RcLogUtil Module in the Global Module Path
C:\windows\system32\WindowsPowershell\v1.0\Modules\RcLogUtil\
that exports the functions
'Out-LogToEventLog','New-LogMessage'
The Plan is to let a specific set of users access only those Logging-Functions.
I create a SessionConfiguration:
New-PSSessionConfigurationFile -Path C:\Scripts\LoggerEp.pssc `
-SessionType RestrictedRemoteServer `
-LanguageMode FullLanguage `
-ExecutionPolicy Unrestricted `
-ModulesToImport 'RcLogUtil' `
-VisibleFunctions 'Out-LogToEventLog' `
-VisibleCmdlets 'Split-Path'
Register it:
Register-PSSessionConfiguration -Path C:\Scripts\LoggerEp.pssc `
-Name loggerep `
-ShowSecurityDescriptorUI
And enter it on my local machine:
[W0216]> Enter-PSSession -ComputerName mka-ps-endpoint -ConfigurationName loggerep
Enter-PSSession : One or more errors occurred processing the module
'RcLogUtil' specified in the InitialSessionState object used to create
this runspace. See the ErrorRecords property for a complete list of
errors. The first error was: The term 'Split-Path' is not recognized
as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that
the path is correct and try again. At line:1 char:1
+ Enter-PSSession -ComputerName mka-ps-endpoint -ConfigurationName loggerep
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (:) [Enter-PSSession], RunspaceOpenModuleLoadException
+ FullyQualifiedErrorId : ErrorLoadingModulesOnRunspaceOpen
The huge question now is.. why is the Session unable to find Split-Path? Or how do I tell the Endpoint to load that particular cmdlet?
I successfully tried the same with SessionType=’Default’ and it worked but with all the powershell clutter around it.
I would really apreciate any help I can get as I am stuck with this for quite some time now..
Thanks!
There is the option to disable each cmdlet in advance by using -SessionType Default with the -ScriptsToProcess 'C:\Scripts\LoggerEpStartup.ps1' Parameter when creating a SessionConfiguration.
New-PSSessionConfigurationFile -Path C:\Scripts\LoggerEp.pssc `
-SessionType Default `
-LanguageMode FullLanguage `
-ExecutionPolicy Unrestricted `
-ModulesToImport 'RcLogUtil' `
-VisibleFunctions 'Out-LogToEventLog' `
-ScriptsToProcess 'C:\Scripts\LoggerEpStartup.ps1'
C:\Scripts\LoggerEpStartup.ps1:
# Commands needed by PSSession (Also the commands used when
# creating a RestrictedRemoteServer )
$CmdsToExclude = #(
'Get-Command' , 'Out-Default' ,
'Exit-PSSession', 'Measure-Object',
'Select-Object' , 'Get-FormatData'
)
# Hide any other commandlets except the ones needed
# to create a remote session
Get-Command | Where Visibility -eq 'Public' | ForEach-Object {
if ( $_.Name -notin $CmdsToExclude ) {
$_.Visibility = 'Private'
}
}
But I want to avoid that aproach as it seems to be more of a clumsy workaround than a proper solution.

Get-WmiObject credentials not working when scheduled

I have a Powershell script to detect disk space on a network server that requires a user/password to access it.
I followed this: http://social.technet.microsoft.com/Forums/en-US/winserverpowershell/thread/440ab7ed-7727-4ff7-a34a-6e69e2dff251/
To get this code:
$password = get-content C:\creds.txt | convertto-securestring
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist "username",$password
Get-WmiObject -ErrorAction Stop Win32_LogicalDisk -ComputerName $deviceName -credential $cred -Filter "DeviceID='$darg'"
$deviceName and $darg are already correctly defined.
This works just fine when running the Powershell script manually. But when I set it up as a Windows schedule task, it fails thinking the user/pass is incorrect:
Get-WmiObject : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESS
DENIED))
$disks = Get-WmiObject <<<< -ErrorAction Stop Win32_LogicalDisk -ComputerName $deviceName -credential $cred -Filter
"DeviceID='$darg'"
+ CategoryInfo : NotSpecified: (:) [Get-WmiObject], Unauthorized AccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Why is this? (The account is a local user on the remote server. I've tried entering the credentials on the Schedule interface but it doesn't let me save it, saying invalid login; maybe due to being a local account) ServerName\LocalUser does not work in the Windows Schedule UI, still gives the incorrect login error.
Here is my comment, re-worded as an answer.
The convertto/from-securestring functions work on a per-user basis (if you don't provide a specific key value). IOW, one user can't read another user's data.
This pre-existing SO question seems relevant. There is also relevant discussion at Powershellcommunity.org.
why dont you set the task to run under the user account and run the wmi request without credential ?