Powershell: how to read an environment variable? - powershell

This is the first powershell script I have attempted. When I run it, part one runs fine and creates the log.txt, but after running it again it still runs part 1. How can I check if the log file exists??
EDIT: I forgot to mention that I am running the script from PowerShell ISE if that makes a difference.
#Variables.
#Set working directory to scripts location.
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
#Check if log file exists.
$ChkFile = "%userprofile%\Desktop\log.txt"
$FileExists = (Test-Path $ChkFile -PathType Leaf)
#Set dir to script location.
Set-Location $dir
#Part 1.
If (!($FileExists))
{
Write-Host "Part 1"
echo 0 >>log.txt
}
#Part 2.
ElseIf ($FileExists)
{
Write-Host "Part 2"
}

% is for cmd.exe variable expansion. You need a different syntax for PowerShell. Instead use:
"$env:userprofile\Desktop\log.txt"

Related

Copy files from my current directory to new directory

so I am trying to copy 2 files from same folder that my Powershell script is in. I have created script there and also 2 files Moveit1.txt, Moveit2.txt my script is this :
$ScriptDirectory = get-childitem -path $PSScriptRoot
Copy-Item $ScriptDirectory\MoveIt1.txt $env:USERPROFILE + "\AppData\Roaming\" -Force
Copy-Item $ScriptDirectory\MoveIt2.txt "C:\Program Files (x86)\" -Force
But unfortunately it says the files can't be found? But if I check just line $ScriptDirectory it shows where its located and with the files inside. What am I doing wrong?
There is one thing to note:
$ScriptDirectory = Get-ChildItem -Path $PSScriptRoot
$scriptDirectory will most likely contain the 2 MoveIt files in addition to your .ps1 script. When you do:
$ScriptDirectory\MoveIt1.txt
I'm guessing it will end up being something like this when interpreted by Copy-Item:
path\to\script\script.ps1\path\to\script\moveit1.txt\path\to\script\moiveit2.txt\moveit1.txt
Try doing this instead:
Copy-Item (Join-Path $PSScriptRoot MoveIt1.txt) (Join-Path $env:USERPROFILE "\AppData\Roaming\") -Force
Copy-Item (Join-Path $PSScriptRoot MoveIt2.txt) "C:\Program Files (x86)\" -Force
Regarding your Access Denied issue and it working when ran as Administrator with hard-coded paths. You can put this at the top of the script so it elevates itself however this will pop an UAC prompt:
$invocation = "-File `"$PSCommandPath`""
Start-Process powershell -Verb Runas -ArgumentList $invocation
The primary problem with your code is a syntax problem (Santiago's helpful answer addresses additional problems):
In order to pass an expression such as
$env:USERPROFILE + "\AppData\Roaming\"
as a command argument, you need to enclose it in (...).
Neglecting to do so passes three arguments, as the following simplified example demonstrates:
# !! WRONG: Passes *three* arguments instead of the result
# of the intended expression.
PS> Write-Output $env:USERPROFILE + "\AppData\Roaming"
C:\Users\jdoe
+
\App\Data\Roaming
# OK: (...) forces a new parsing context, in which the expression is recognized
# as such.
PS> Write-Output $env:USERPROFILE + "\AppData\Roaming"
C:\Users\jdoe\App\Data\Roaming
As an aside:
You could use $env:APPDATA to directly get the path of interest, and
Even in cases where you do need to build a path from multiple strings, it may be simpler to use an expandable string instead of the + operator: "$env:USERPROFILE\AppData\Roaming" - in this particular case, because the string contains neither spaces nor other special characters (other than the intended $), the double quotes are even optional.
See this answer for more information.
try {
$scriptPath = $PSScriptRoot
if (!$scriptPath)
{
if ($psISE)
{
$scriptPath = Split-Path -Parent -Path $psISE.CurrentFile.FullPath
} else {
Write-Host -ForegroundColor Red "Cannot resolve script file's path"
exit 1
}
}
} catch {
Write-Host -ForegroundColor Red "Caught Exception: $($Error[0].Exception.Message)"
exit 2
}
Write-Host "Path: $scriptPath"
Copy-Item $ScriptPath\onexcuiconcif.xml -Destination "$env:APPDATA\Avaya\Avaya one-x Communicator" -Force
Copy-Item $scriptPath\InstallConfig.xml -Destination "C:\Program Files (x86)\Avaya\Avaya one-X Communicator" -Force

$MyInvocation.MyCommand.Name return null value after converting ps1 to exe

powershell script results in incorrect output after converting it to an .exe-file and executing it:
$MyScriptName = $MyInvocation.MyCommand.Name
Above is snippet of my powershell code, which works fine and saves the script name in the $MyScriptName variable.
Once we convert the .ps1-script to an .exe-file and execute it, the variable $MyScriptName has a null value.
Script related variables become unavailable after converting the script to an executable file. You can find information about it here on Markus Scholtes' release page on Github for the PS2EXE-GUI version (Win-PS2EXE): PS2EXE-GUI
Here's the code you need to add to your script.
if ($MyInvocation.MyCommand.CommandType -eq "ExternalScript")
{ $ScriptPath = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition }
else
{ $ScriptPath = Split-Path -Parent -Path ([Environment]::GetCommandLineArgs()[0]) }

In Powershell, how to create a directory using IP address into a remote computer using do-while loop

Please help me. I'm trying trying to create a PowerShell script using do-while loop as follows:
Ask user for folder name (foldername) and target IP Address (targetipaddress)
If "foldername" does not exist, then create "foldername" in "C:\" drive
Using "targetipaddress" as the part of target path, copy the contents from a sub folder of network drive path,"S:\" and paste into the "foldername" in the "C:\" path.
If user enters "quit", then script finishes.
My code below:
$var = "welcome to IP address and folder creation world"
echo $var
# create foldername until user type "quit"
$output = (command)
do {
$foldername = Read-Host "enter folder name "
$targetipaddress = Read-Host "enter target ip address "
# create folder name only if it does not exist
function createFolder {
$path = "\\$targetipaddress\C$\$foldername "
If (!(Test-Path $path))
{
New-Item -ItemType Directory -Force $path
}
} # end of function createFolder
# copy contents from a sub folder of a network drive path and
# and paste them onto "C:\" drive path using "targetipaddress" and "foldername"
function copyContents {
Copy-Item S:\sourcefolder\subfolder\*.* \\$targetipaddress\C$\$foldername\ -Recurse
}
} while ($foldername = "quit") # end of do-while loop
See below for a working example, read carefully and compare this one with your own.
Some of the problems / changes.
echo? it should be write-host
unnecessary and unused functions.
$output = (command), it does nothing.
do while, i like to use while($true) and break out of it.
optional, error handling.
powershell does not use = (i believe you meant ==) for equels logic but -eq
a few other problems / changes.
some reading materials:
Comparison Operators See link from Mike Sherrill 'Cat Recall'
Continue
Break
If you get an error with this code please post the inputs voor $source, $foldername, $targetipaddress and $path and i will look at it.
Code:
clear-host #clears your console, optional.
$ErrorActionPreference = "Stop" #prevents al lot of posible disasters from happening.
Write-Host "welcome to IP address and folder creation world" #Powershell way of writing to the console.
$source = "S:\sourcefolder\subfolder\*"
#$source = "C:\source\*" i used this for testing on my local machine.
# create foldername until user type "quit"
While ($true){
"
"#Add some white space between the questions.
$foldername = Read-Host "enter folder name "
If ($foldername -eq "quit") {break} #exit the while loop
$targetipaddress = Read-Host "enter target ip address " #you could use a hostname to.
$path = "\\$targetipaddress\C$\$foldername"
#if connection to targetipaddress fails then abort.
if(!(Test-Connection $targetipaddress -ErrorAction SilentlyContinue)) #look at the ! it means it should be false.
{
Write-Warning "Could not connect to '$targetipaddress'"
continue #goes back to the begining of the while loop.
}
#if path does not exist try to create it.
if(!(Test-Path $path)) #look at the ! it means it should be false.
{
try { New-Item -ItemType Directory -Path (Split-Path -Parent $path) -Name $foldername | Out-null } #Out-null prevenst unwanted console output.
catch {
Write-Warning "Could not create folder '$foldername' on '$targetipaddress'"
continue #goes back to the begining of the while loop.
}
}
#try to copy files.
try { Copy-Item -Path $source -Destination $path -Recurse -Force }
catch {
Write-Warning "An Error occured while copying the files from '$source' to '$path'"
continue #goes back to the begining of the while loop.
}
#if all goes well then tell them ;)
Write-Host "files copied successfully from $source to $path"
}

How to pipe embedded script to powershell

I adapted some code from a solution here, but it doesn't work for me when executed as a bat script. Executed within a bat script, it gives the error below. Executed on the command line (with the correct line number as calculated by the script in place of %Line%, it works fine.
The key line is
more +%Line% %0 | powershell -c –
The error is
û : The term 'û' is not recognized as the name of a cmdlet, function, script file, or operable program.
The full Bat script is
#echo off
set fn=Archive-Extract
set fnp0=C:\RMT\VCS\GIT\Games\soulfu\build\dependencies2\libogg-1.2.2.zip
set fnp1=C:\RMT\VCS\GIT\Games\soulfu\build\dependencies2
::::::::::::::::::::::::::::::::::::
REM Set %A to the line number of all lines starting with ':', this leaves %A with the line number of the last ':'.
for /f "delims=:" %%a In ('findstr /Bn ":" %0') do set /A Line=%%a
REM Send the content of this script past the last line starting with ':' to powershell.
more +%Line% %0 | powershell -c –
::::::::::::::::::::::::::::::::::::
dir *.bat
pause & exit /b
::::::::::::::::::::::::::::::::::::
function Archive-Extract([string]$zipFilePath, [string]$destinationPath) {
# This will get added when paths are joined, and path comparison will need it to be absent.
$destinationPath = $destinationPath.TrimEnd("\");
[Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem');
$zipfile = [IO.Compression.ZipFile]::OpenRead($zipFilePath);
# Determine how many top level entries there are.
$ziplevel0files = #{};
$zipfile.Entries | foreach {
$s = ($_.FullName.TrimEnd("/") -split "/")[0];
if ($ziplevel0files.ContainsKey($s)) {
$ziplevel0files[$s] = $ziplevel0files[$s] + 1;
} else {
$ziplevel0files[$s] = 0;
}
}
if ($ziplevel0files.count -ne 1) {
Write-Host "Zip archives are (at this time) expected to contain one top-level directory, and all content within it.";
return 1; # Failure
}
$zipDirPath = Join-Path -Path $destinationPath -ChildPath $ziplevel0files.Keys[0];
# If the directory does not exist, extract the zip archive into the current folder.
if (Test-Path -LiteralPath $zipDirPath) {
Write-Host "Top-level extraction directory already exists.";
return 2; # Failure
}
$zipfile.Entries | foreach {
$extractFilePath = Join-Path -Path $destinationPath -ChildPath $_.FullName;
$extractFileDirPath = Split-Path -Parent $extractFilePath;
# Skip the top-level directory everything comes under.
if ($extractFileDirPath -ne $destinationPath) {
if (-not (Test-Path -LiteralPath $extractFileDirPath -PathType Container)) {
New-Item -Path $extractFileDirPath -Type Directory | Out-Null;
}
# Sometimes a directory comes after a file within the directory (the latter causes it to be created implicitly above).
if (-not $extractFilePath.EndsWith("\")) {
try {
[IO.Compression.ZipFileExtensions]::ExtractToFile($_, $extractFilePath, $true);
} catch {
Write-Host "Failed to extract file:" $extractFilePath;
return 3; # Failure
}
}
}
}
return 0; # Success
}
# Anything that calls should execute the powershell and set the parameters.
$fn = (Get-ChildItem Env:fn).Value;
$f = (get-item -path function:$fn);
Write-Host "sss1" $fn;
if ($fn -eq "Archive-Extract") {
Write-Host "sss2";
$archivepath = (Get-ChildItem Env:fnp0).Value;
$destinationpath = (Get-ChildItem Env:fnp1).Value;
$err = & $f.ScriptBlock $archivepath $destinationpath;
exit $err;
} else {
Write-Host "sss3";
Write-Error "Failed to match function: "+ $fn;
exit 1000;
}
What needs to be added to the BAT script to execute the same as when the code is executed line-by-line on the command-line?
EDIT: Note that when I adapted this script to follow the multi-line powerscript commenting approach recommended by npocmaka, the existing code above based on more but with no skipped line numbers worked. However, I am not entirely convinced that this solves the problem. I believe the above code worked fine at one point, as is, and worked for the person who came up with the original base code to begin with.
<# :
#echo off
echo --START POWERSHELL--
:: $cmdargs variable will contain the command line.
powershell $cmdargs="""%*""";$exp=$(Get-Content '%~f0') -replace """`n""",""";""" ;invoke-expression """$exp"""
echo --START BATCH--
dir *.bat
pause & exit /b
#>
Write-Host "sss";
exit;
Try this.I think it's better way for hybridization and allows something like argument passing to powershell script.Just have in mind that every line should be terminated with ;

How to write to all users appdata folder?

I have a script that writes to a file in %username\AppData
$path = "c:\program files (x86)\java\jre6"
$user = $env:username
if(test-path $path)
{
add-content "c:\users\$user\AppData\locallow\sun\java\deployment\deployment.properties" "deployment.javaws.jre.0.args=-Xms512m"
exit 0
}
elseif(!(test-path $path))
{
exit 1
}
However, I need to run this script as an administrator. Which means I can't run it for the current user, making the $env:username variable useless.
How can I change this script so that it modifies the AppData of every user on the computer?
I notice you're adding something to Java's deployment.properties file. I recently went through this and instead of changing the setting for each user you can move the file to C:\Windows\System32\Sun\Java instead and all users will reference the same file. Here's some instructions.
Do a ForEach (alias % used) loop on all the folders found in C:\Users
$path = "c:\program files (x86)\java\jre6"
$user = $env:username
if(test-path $path)
{
GCI C:\Users -Directory | %{add-content "$($_.FullName)\AppData\locallow\sun\java\deployment\deployment.properties" "deployment.javaws.jre.0.args=-Xms512m"
exit 0
}
elseif(!(test-path $path))
{
exit 1
}