Showing posts with label powershell. Show all posts
Showing posts with label powershell. Show all posts

Saturday, October 12, 2019

Powershell Script to append environment variable PATH in windows

Powershell Script to append environment variable PATH in windows

#Requires -RunAsAdministrator
<#
.Synopsis
   Script to append environment variable with new path
.DESCRIPTION
   This script will add a required path to path in windows environment variable
   Requires admin powershell prompt
   This script modifies registery, running without understanding might corrupt your windows installation
.EXAMPLE
   .\script.ps1 -PathToAdd "C:\program files\programname\bin"
#>
param(
[Parameter(Mandatory=$True,ValueFromPipeline=$True)]
[ValidateNotNullOrEmpty()]
[string[]]$PathToAdd
)
         
process{
    foreach($path in $PathToAdd)
    {
        try
        {
           Write-Warning "Path : $path"
           Test-Path (Resolve-Path $path -ErrorAction Stop) | Out-Null
  
            $currentPathStrings = (Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).path.split(';')
            $currentPathStrings = $currentPathStrings | ? {$_.trim()}
            $pathToSave = $currentPathStrings + $path
            $pathStringToWrite = $pathToSave -join ';'
            Write-Warning "Writing below paths"
            Write-Output $pathStringToWrite
            try
            {
                Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH -Value $pathStringToWrite -ErrorAction Stop
            }
            catch
            {
                Write-Warning "Error writing to registry"
                Write-Output $_
            }
        }
        catch
        {
            Write-Warning "Above path you are trying to add could not be resolved, please check if it is a plain path and accessible from file explorer"
        }
    }
}

Saturday, March 19, 2016

Run powershell on remote machine without enabling powershell remoting !

Here is a tricky way to execute powershell code on remote machine without actually enabling powershell remoting. Enabling powershell remote lets you run powershell commands on a remote machine and get the output on to your computer.

You can either use the -ComputerName parameter available in a command or use the Invoke-Command using the -Computer parameter, or create a psremoting session and run the Invoke-Command on the session.

If PSRemoting is not enabled on your environment you do not have any way to run powershell script on a remote machine.

I was creating a remote software installation tool using powershell which wraps the PsExec tool and lets you install a software on remote machine if you know the silent installation commandlines. With a slight modification same tool can be used for running a script on the remote machine and get the outputs.

PSExec redirects the output onto your screen but if you create an output file on the remote machine you need to figure a way to get it copied onto your local machine from the remote machine, or create a share in your localmachine/server to which you can save the output from the remote machine.

Script uses the cmdkey to cache the credentials and maps the remote machine C drive to copy the setup files.

Creates a folder in C drive on the remote machine, copies the ps1 file you want to run along with a batch file which triggers the powershell script.

Once the script execution is completed on the remote machine, mapped network drive and cached credentials will be deleted.

GUI creation credit to following blog.
Download psexec and save it in the same folder where you have the main script.

The below script can be run using the remote machine name and the ps file source folder name.

Here is how your script folder should look like.








Before running the script, want to show that the remote machine has a restricted powershell execution policy and PSremoting is not enabled(Screenshot1).
Below  script would be run on this machine from a different machine.

$process = Get-Process
$process
Write-Host "Also writing output to file on remote machine check C:\temp\lanabhat.txt"
$process | Out-File C:\temp\Lanabhat.txt
 
How to run the script.

Commandline entered in the installCommand.bat file
powershell -ExecutionPolicy ByPass C:\Software_Install\test-remoteShare.ps1

Running the powershell script.
.\Run-PowershellRemote.ps1 -MachineName PC0001 -installSourceFiles C:\Users\lanabhat\Desktop\Remote-Powershell\test-powershellscript

Credentials to connect to the remote machine, username would default to COMPUTARENAME\Administrator , if you have a service account or a domain admin account, you can modify the code and replace it to default to that value.


Remote machine C drive is mapped to P drive a folder is created to batch file and powershell script is copied to that folder and batch file is executed with system account.

Credential will be cached to connect to run psexec on remote machine. It will be removed at the end.

Output of the script is shown in your machine but the script is running on the remote machine.


Once the execution is completed press enter to do clean-up. Files copied to remote machine will be deleted and shared folder will be unmapped.

Here is the result from the remote machine.

And finally here is the script.

Please share your feedback and send me a message if you find it useful !


<#
.Synopsis
   Run powershell script on remote machine using psexec
.DESCRIPTION
   Copies the setup files specified in the source.
   This script runs the commandline from the installCommand.bat file on remote machine.
   Copies the setup files to remote machine
   Executes the installation.
.EXAMPLE
   .\Run-PowershellScript.ps1 -MachineName "hostname1" -installSourceFiles \\sharename\foldername -Verbose
.EXAMPLE
   .\Run-PowershellScript -MachineName "hostname2" -installSourceFiles \\sharename\foldername -Verbose
 
#>

    [CmdletBinding()]
    
    Param
    (
        #Machine Name
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        $MachineName,

        #Shared folder location of setup.
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=1)]
        $installSourceFiles
     )

#region functions
Function Get-RandomDriveLetter
{
$drive=ls function:[d-z]: -n|?{!(test-path $_)}|random
$dl=($drive.ToString()).Replace(":","")
$dl
}


Function map-Drive($driveLetter,$networkDrive,$creds)
{
  $errorFlag = $false

  $net = new-object -ComObject WScript.Network
  
  Write-Verbose "Drive letter $driveLetter"
  Write-Verbose "Network share $networkDrive"

  
  $user_cred = $creds #Get-Credential -Message "Enter the admin cred to map C: drive" $userID

  if($user_cred -eq $null)
  {
   "Credentials were not entered, cannot proceed"
   return 0
  }
  
   $networkCred = $user_cred.GetNetworkCredential()
   $password=$networkCred.Password
   $userID=$networkCred.Domain + "\" + $networkCred.UserName
   $driveLetter += ":"
  
   try
   {
    $net.MapNetworkDrive($driveLetter,$networkDrive,$false,$userID,$password)
   }
   catch
   {    
    $errorFlag = $true
    $ErrorMessage = $_.Exception.Message
    if($ErrorMessage -match "The specified network password is not correct")
    {
     Write-Host "Invalid credentials" -ForegroundColor Yellow
    }
    else
    {
     Write-Host "Invalid credentials" -ForegroundColor Yellow
    }

    exit 0
}



}

#Unmap the network drive
Function Unmap-NetworkDrive($driveLet)
{
  Remove-PSDrive -Name $driveLet
}

function Cache-Creds($hostname,$username,$password)
{
  cmdkey.exe /add:$hostname /user:$userName /pass:$password
}

function Remove-CacheCred($hostname)
{
cmdkey.exe /delete:$hostname
}

#endregion functions


$localSetup = "Software_Install" #Local folder which will be created on C drive on user machine
$batchFile = "$($Script:PSScriptRoot)\installCommand.bat" #Command file which will be copied to user machine
$remoteBatchPath = "C:\$($localSetup)\installCommand.bat"

#create a batch file as per the script argument
Write-Verbose "Commandline used is: $commandLine"

$hostname =  $MachineName
$userName = "$($hostname)\administrator"
$credential=Get-Credential $userName -Message "Please center the password to access the remote machine"
$password = $credential.GetNetworkCredential().Password;

#Create a cached credentials for psexec connection
Cache-Creds $hostname $username $password

$remMachinedriveLetter = Get-RandomDriveLetter
$sharePath = "\\$($hostname)\C$"

#Map the remote machine C drive
map-Drive $remMachinedriveLetter $sharePath $credential

#Created SCCM_Install folder on c drive, if it does not exists
if(!(Test-Path "$($remMachinedriveLetter):\$localSetup"))
{
Write-Verbose "Directory not found on remote server, creating the directory: $($remMachinedriveLetter):\$localSetup"
New-Item -path "$($remMachinedriveLetter):\$localSetup" -ItemType Directory
}

#Copy setup files to remote machine
Write-Verbose "Copying setup files from $installSourceFiles"
Copy-Item "$($installSourceFiles)\*" "$($remMachinedriveLetter):\$localSetup\" -Recurse -Verbose -Force -Container

Write-Verbose "Copying batchfile : $batchFile"
Copy-Item $batchFile "$($remMachinedriveLetter):\$localSetup\" -Verbose

#run psexec and launch install
Write-Verbose "Running PSEXEC to trigger the batch"
& .\psexec.exe \\$hostname -h -s $remoteBatchPath

Write-Host "Exitcode:" -ForegroundColor Yellow
$LASTEXITCODE

#Unmap network drive, cleanup
Write-Verbose "Removing Cached Creds"
Remove-CacheCred $hostname


Read-Host "Press enter to do cleanup"
Write-Verbose "Deleting installation files"
Remove-Item "$($remMachinedriveLetter):\$localSetup" -Recurse -Verbose


Write-Verbose "Removing network drive"
Unmap-NetworkDrive -driveLet $remMachinedriveLetter


Coming next -

Remote software installer, merging the power of powershell and psexec....
































Wednesday, December 16, 2015

SCCM 2012:: Powershell:: Script to get the SCCM server log files and their location details and export it to an HTML report

This script will give you the list of log files for each components installed on each server on your SCCM infrastructure.

Script can be run from CAS server.

Add your CAS Servername and CAS site code to the script.

An HTML file will be generated on your desktop which shows you the log file path and link to directly open the log file from the machine from where you are running the script.

 Powershell remoting should be enabled on all servers.

The output would be similar to the below screenshot.


  
Note: This does not cover the SMSDPProv.log and smsdpusage.log

Thursday, June 18, 2015

Initiate a machine policy or user policy on the client machine/members of a collection

Very useful command which can trigger the client machine policy/user policy action. Can be triggered for a device or a collection.

Whenever I deploy an application to a set of my test machines, I would trigger this action from the SCCM powershell console which would make the deployment available quickly on the machine.

Example: 

Invoke-CMClientNotification

 

Invoke-CMClientNotification -DeviceCollectionName "CollectionName" -NotificationType RequestMachinePolicyNow -Verbose 

Refer: https://technet.microsoft.com/en-us/library/dn472965%28v=sc.20%29.aspx



Friday, June 5, 2015

Powershell:SCCM2012:How to enable Binary Differential Replication or Delta Replication property of a package


Function enableDeltaReplication($SiteServer,$SiteCode,$Namespace,$pkgId)
{
    $USE_BINARY_DELTA_REP = "0x04000000" #Property of SMS_PackageBaseclass for Delta replication. Refer: https://msdn.microsoft.com/en-us/library/cc146062.aspx

    $myPackage = Get-WmiObject -Namespace $Namespace -ComputerName $SiteServer -Query "SELECT *  FROM SMS_PackageBaseclass Where PackageID = '${pkgId}'"
    $res=$myPackage.PkgFlags -bor $USE_BINARY_DELTA_REP
    $myPackage.PkgFlags=$res
    $myPackage.Put()

    $myPackage = Get-WmiObject -Namespace $Namespace -ComputerName $SiteServer -Query "SELECT *  FROM SMS_PackageBaseclass Where PackageID = '${pkgId}'"
    if($myPackage.PkgFlags -band $USE_BINARY_DELTA_REP) {return $true} Else {return $false}
}

# $pkgid = package id of the package to enable binary differential replication

#refer get-cmpackage to obtain package id.



$siteCode="SITE_CODE" #Your CAS site code$replRes=enableDeltaReplication "Your_CAS_ServerName" $siteCode "root\sms\site_$($SiteCode)" $pkgid

Write-Host "Binary replication result ${replRes}"