Calling param object inside script block - powershell

I am trying to create a folder remotely but the parameter that I type in command line doesn't pass in script block. Below code will only create directory webapp.
$computerName = "s3apdev0074"
Invoke-Command -ComputerName $computerName -ScriptBlock { param([string]$appname) md d:\webapp\$appname}

Please try this:
$ComputerName = 's3apdev0074'
$AppName = Read-Host "Please enter the application name"
Invoke-Command -ComputerName $ComputerName -ArgumentList $AppName -ScriptBlock {
Param (
[String]$AppName
)
# DOS:
md d:\webapp\$AppName
# PowerShell: New-Item -Path "d:\webapp\$AppName" -ItemType Directory
}
It seem you are only missing the -ArgumentList parameter to pass in your local variable.
More info here:
Get-Help Invoke-Command -Parameter ArgumentList

Related

Remotely setting wallpaper on demand via powershell

I have created a function Set-Wallpaper:
Function Set-WallPaper($Value)
{
Set-ItemProperty -path 'HKCU:\Control Panel\Desktop\' -name wallpaper -value $value
rundll32.exe user32.dll, UpdatePerUserSystemParameters
}
and can run it locally to use a network path to the desired jpg
Set-Wallpaper -value "\\server\share\image.jpg"
and it works.
Now I want to run this function on a remote PC, I tried
Invoke-Command -ComputerName TARGETPC Set-Wallpaper -value "\\server\share\image.jpg"
but it errors out with
Invoke-Command : A parameter cannot be found that matches parameter name 'value'.
what am I missing?
$session= new-pssession -Computername "yourClientname"
$reslt= Invoke-Command -Session $session -ScriptBlock {your code}
If u want to ahnd over an argument use it like this
$reslt= Invoke-Command -Session $session -argumentlist $argument -ScriptBlock {param ($argument) your code with $argument[0]}

Problem with test-path on computer from another domain

Im trying to test a remote folder in a computer from another domain with -credential
This command works fine:
Invoke-Command -ComputerName "server" -credential domain\user -ScriptBlock {Test-Path -Path "\\server\s$\temp"}
But if i use it in a script fails:
$servers = Get-Content "servers.txt"
$Path = "\\D$\Temp"
$cred = "domain\user"
ForEach ($server in $servers) {
if (invoke-command -computername $server -credential $cred -ScriptBlock {Test-Path -Path "\\$server\$Path"})
}
PD: All this option works in a server of my domain without specify another credentials.
Besides the syntax issue with missing the script block after your if statement, this should work as long as you specify the variables as remote ones. Use $using or pass it as an argument with -ArgumentList.
$servers = Get-Content "servers.txt"
$Path = "\\c$\Temp"
$cred = "domain\user"
ForEach ($server in $servers) {
if (
invoke-command -computername $server -ScriptBlock {
Test-Path -Path "\\$using:server\$using:Path"
}
) { <#do code here#> }
}
If you run the shell with the proper credentials to begin with, all youd have to do is use Test-Path directly but I understand that you'd like to try using the -Credential parameter.

How to pass variable in Scriipt Block for use with Invoke-Command that will call an executable that takes the variable as switch param

I am attempting to create a generic script that will process registry files on a list of remote servers. The script will take the input of the path/filename to process and a list of servers to process it on. Copies the .reg file to the remote server and then attempts to process the .reg file on the remote server. In order to make it generic for use with any .reg file I want to pass the path\filename to process in a variable in the script block. I have seen examples of passing named variables and positional parameters but that doesn't seem to meet my requirements. I tried creating the script block contents as a Scriptblock type and calling it but it does not work. Most of the errors I have been getting are related to invalid parsing, ambiguous parameter, etc. I have seen a couple of working examples in which the .reg file path/filename is hard-coded but that defeats the purpose of what I am attempting to accomplish. I have tried the Invoke-Command with a session and with the -ComputerName variable in order to try the :using:" command with no success. Is there any way to pass a variable that is basically the command line values (switch params & filepath/name) for an executable within the scriptblock or am I going about this in the wrong manner? In code below I am crossing domains so having to open session for those servers in order to create directory if it doesn't exist.
while ($true)
{
$regFile = Read-Host -Prompt "Enter the path & name of registry file to be processed"
If(Test-Path -Path $regFile) { break }
Write-Host "You must enter valid path & filename of a registry file to process."
}
$servers = Get-Content D:\MLB\Scripts\servers.txt
$fileNm = [System.IO.Path]::GetFileName($regFile)
$pass = ConvertTo-SecureString "blahblah" -AsPlainText -Force
$Creds = new-object -typename System.Management.Automation.PSCredential( "domain\username", $pass)
foreach ($server in $servers)
{
$dirPath = ''
$newfile = '\\' + $server + '\d$\MLB\RegFiles\' + $fileNm
if($server.ToLower().Contains("web"))
{
$Session = New-PSSession -ComputerName $server -Credential $Creds
Invoke-Command -Session $Session -ScriptBlock { New-Item -ErrorAction SilentlyContinue -ItemType directory -Path D:\MLB\RegFiles }
$newfile = "d:\MLB\RegFiles\" + $fileNm
Copy-Item $regFile -Destination $newfile -ToSession $Session -Force
Remove-PSSession -Session $Session
}
else
{
$dirPath = "\\$server\d`$\MLB\RegFiles"
New-Item -ErrorAction SilentlyContinue -ItemType directory -Path $dirPath
$newfile = "\\$server\d`$\MLB\RegFiles\$fileNm"
Copy-Item $regFile -Destination $newfile -Force
}
Invoke-Command -ComputerName $server -Credential $Creds -ScriptBlock {
$args = "s/ $newfile"
Start-Process -filepath "C:\Windows\regedit.exe" -Argumentlist $args
}

How to run script against windows servers WinRM

I am trying to run a script that searches/downloads/installs windows updates on remote computers using WinRM. I am running this script as a domain user with Admin access. However, I get an ACCESS Denied error.
Now, I have the script copied over to the remote servers but I am unable to view output to see whether the script is running or not.
OUTPUT I want to see:
# Continue running on other servers on error
$ErrorActionPreference = "Continue"
# Server list
$servers = Get-Content "C:\Users\admin\Desktop\vm-nonprod.txt"
# Logs
$log = "C:\Users\admin\Desktop\log-nonprod.txt"
# Path to script on server list
$scriptpath = "C:\Patch.ps1"
$results = #()
foreach ($server in $servers) {
try {
$Credential = Import-CliXml -Path "C:\Users\admin\Desktop\admin.Cred"
#New-PSSession -ComputerName $server -Credential $Credential
Invoke-Command -ComputerName $server -Credential $Credential -ScriptBlock {$scriptpath} -ArgumentList "Y" | Out-File -FilePath C:\Users\admin\Desktop\WinPatch.txt
#Invoke-Command -ComputerName $server -Credential hhq\admin -FilePath "C:\Users\admin\Documents\Patch.ps1"
#Copy-Item -Path C:\Users\admin\Documents\Patch.ps1 -Destination 'C:\' -ToSession (New-PSSession –ComputerName $server -Credential $Credential)
}
catch {
Write-Output ("Error running script on remote host: " + $server)
}
}
$results | Export-Csv -NoTypeInformation $log
There's a few issues here.
Does the script exist on the server?
Sounds like yes, you have Patch.ps1 in C:\ on each $server
The scriptblock does not run the script - just prints the variable.
To run it, change {$scriptpath} to {. $scriptpath} or {& $scriptpath}
The variable $scriptpath is not in the scriptblock scope - you will have to pass it in the -ArgumentList
Change: {$scriptpath} -ArgumentList "Y"
____To: {param($p); . $p} -ArgumentList $scriptpath
The argument "Y" is being passed to the scriptbock, not the script. The scriptblock is not looking for it, so this value is being lost.
Assume you want it to be passed to the script - this needs to be done in the scriptblock:
{$scriptpath "Y"}
I would recommend getting rid of Out-File until you are happy with the output in the console.
Putting it all together:
-ScriptBlock {$scriptpath} -ArgumentList "Y" | Out-File -FilePath C:\Users\admin\Desktop\WinPatch.txt
-ScriptBlock {param($p); . $p "Y"} -ArgumentList $scriptpath
I believe you have the wrong Invoke-Command commented out. The one that is running only has the user name hhq\admin in the credential parameter. It might be failing due to that because it would be prompting for the password during run-time.

Remote Registry using Enter-PSSession

I am trying to read strings in a remote registry. When I run the script I am working on, it connects to the workstation in the list, but it only reads the local computer when running, not the remote. any Ideas?
#create open dialog box
Function Get-FileName($initialDirectory)
{
[void] [Reflection.Assembly]::LoadWithPartialName( 'System.Windows.Forms' );
$d = New-Object Windows.Forms.OpenFileDialog;
$d.ShowHelp = $True;
$d.filter = "Comma Separated Value (*.csv)| *.csv";
$d.ShowDialog( ) | Out-Null;
$d.filename;
}
# Set Variables with arguments
$strFile = Get-FileName;
$strComputer = Get-Content $strFile;
$date = Get-Date -Format "MM-dd-yyyy";
$outputFile = "C:\PowerShell\Reports";
$cred = Get-Credential
foreach($computer in $strComputer)
{
Enter-PSSession $computer -Credential $cred
Set-Location HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability
$systemInfo = Get-Item -Name LastComputerName
Write-Host $systemInfo
}
foreach($computer in $strComputer)
{
Enter-PSSession $computer -Credential $cred
..
..
}
The above code won't work. Enter-PSSession is not for using in a script. Anything written after that in a script won't run.
Instead, use Invoke-Command and pass rest of the script block as a parameter value. For example,
foreach ($computer in $strComputer) {
Invoke-Command -ComputerName $computer -Credential $cred -ScriptBlock {
Set-Location HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability
$systemInfo = Get-Item -Name LastComputerName
Write-Host $systemInfo
}
}
As the comments already explained, Enter-PSSession is for interactive use. To read remote registry entries, there are several ways.
Use plain reg.exe, it works well enough. Like so,
foreach($computer in $strComputers) {
reg query \\$computer\hklm\software\Microsoft\Windows\CurrentVersion\Reliability /v LastComputerName
}
Use PSSessions. Create a session and Invoke-Command to read registry. Like so,
function GetRegistryValues {
param($rpath, $ivalue)
Set-Location $rpath
$systemInfo = (Get-ItemProperty .).$ivalue
Write-Host $systemInfo
}
$session = New-PSSession -ComputerName $computer
Invoke-Command -Session $session -Scriptblock ${function:GetRegistryValues} `
-argumentlist "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability",`
"LastComputerName"
Remove-PSSession $session
Use .Net classes, Microsoft.Win32.RegistryKey. Like so,
$sk = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $server)
$k = $sk.opensubkey("SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability", $false)
write-host $k.getvalue("LastComputerName")