Link to home
Start Free TrialLog in
Avatar of Cyber IT
Cyber ITFlag for United States of America

asked on

Powershell Help -- if else trigger file

Hello
I'm trying to create an if statement that with produce a text file that depends on the location.

Right now I have a text file being produced after 5 locations are met but I want to change that and code in an if statement indicating if location1 meets then produce location1.txt. If location2 meets then produce location2.txt else produce location.txt for the other locations.

Any help is much appreciated. Thanks!
Avatar of Qlemo
Qlemo
Flag of Germany image

Can you show some code so we can get an idea of what aldeady have? We would be able to post very generic info only without.
Avatar of Cyber IT

ASKER

$Loc1DNSSearchOrder = ("x.x.x.x")
$Loc2DNSSearchOrder = ("x.x.x.x")
$Loc3DNSSearchOrder = ("x.x.x.x")
$Loc4DNSSearchOrder = ("x.x.x.x")
$Loc5DNSSearchOrder = ("x.x.x.x")

$adapters = Get-WmiObject Win32_NetworkAdapterConfiguration -filter "IPEnabled = True and DHCPEnabled = False" | Where-Object {$_.DNSServerSearchOrder}
$win_ver=(Get-WmiObject win32_operatingsystem).version

#get network_location
#$fact_var=facter | findstr network_location
#$fact_var=$fact_var -split ">"
#$loc=$fact_var[1]
#$loc=$loc.trim()

$factloc = "C:\ProgramData\PuppetLabs\facter\facts.d\" 
If ($win_ver -lt 6){ 
        $factloc = "C:\Documents and Settings\All Users\Application Data\Puppetlabs\facter\facts.d\" 
} 

$dc_file=$factloc + 'network_location.txt' 
$factfile = Test-Path $dc_file 
if ($factfile -eq $true) 
    { 
    $net_loc=Get-Content $dc_file 
    $dc_arr=$net_loc -split "=" 
    $loc=$dc_arr[1] 

    switch ($loc)
        {
            'Loc1' {$adapters.SetDNSServerSearchOrder($Loc1DNSSearchOrder)}
            'Loc1_d' {exit 1}
            'Loc2' {$adapters.SetDNSServerSearchOrder($Loc2DNSSearchOrder)}
            'Loc2_d' {exit 1}
            'Loc3' {$adapters.SetDNSServerSearchOrder($Loc3DNSSearchOrder)}
            'Loc3_d' {exit 1}
            'Loc4' {$adapters.SetDNSServerSearchOrder($Loc4DNSSearchOrder)}
            'Loc5' {$adapters.SetDNSServerSearchOrder($Loc5DNSSearchOrder)}
        default {exit 1}
        }
    #create our trigger file
    echo "dns setup" > C:\os_config\trigger\location.txt

Open in new window

At the end Im trying to get an if and else statement so I can create different trigger files.  All locations get the current trigger file but I dont want that ... I want Loc1 to get Location1, Loc2 to get Location2, etc.  Thanks in advance!

   #create our trigger file
    echo "dns setup" > C:\os_config\trigger\location.txt

Open in new window

One possible way is that you simply extract the number from the $loc variable.
$Loc1DNSSearchOrder = ("x.x.x.x")
$Loc2DNSSearchOrder = ("x.x.x.x")
$Loc3DNSSearchOrder = ("x.x.x.x")
$Loc4DNSSearchOrder = ("x.x.x.x")
$Loc5DNSSearchOrder = ("x.x.x.x")

$adapters = Get-WmiObject Win32_NetworkAdapterConfiguration -filter "IPEnabled = True and DHCPEnabled = False" | Where-Object {$_.DNSServerSearchOrder}
$win_ver=(Get-WmiObject win32_operatingsystem).version

#get network_location
#$fact_var=facter | findstr network_location
#$fact_var=$fact_var -split ">"
#$loc=$fact_var[1]
#$loc=$loc.trim()

$factloc = "C:\ProgramData\PuppetLabs\facter\facts.d\" 
if ($win_ver -lt 6) { 
        $factloc = "C:\Documents and Settings\All Users\Application Data\Puppetlabs\facter\facts.d\" 
} 

$dc_file = $factloc + 'network_location.txt' 

if (Test-Path $dc_file) {

    $net_loc = Get-Content $dc_file 
    $dc_arr = $net_loc -split "=" 
    $loc = $dc_arr[1] 

    switch ($loc) {
        'Loc1'   { $adapters.SetDNSServerSearchOrder($Loc1DNSSearchOrder) }
        'Loc2'   { $adapters.SetDNSServerSearchOrder($Loc2DNSSearchOrder) }
        'Loc3'   { $adapters.SetDNSServerSearchOrder($Loc3DNSSearchOrder) }
        'Loc4'   { $adapters.SetDNSServerSearchOrder($Loc4DNSSearchOrder) }
        'Loc5'   { $adapters.SetDNSServerSearchOrder($Loc5DNSSearchOrder) }
        default  { exit 1 }
    }

    $number = $loc -replace '^loc'
    # create our trigger file
    "dns setup" > "C:\os_config\trigger\location$number.txt"
}

Open in new window

I assume that locations are placeholders only, and you cannot simply extract a number ...
if that's so, an alternative is to load up the switch statement. I'd considered it, but it's a bit messy.
    switch ($loc) {
        'Loc1'   { $adapters.SetDNSServerSearchOrder($Loc1DNSSearchOrder); $number = 1 }
        'Loc2'   { $adapters.SetDNSServerSearchOrder($Loc2DNSSearchOrder); $number = 2 }
        'Loc3'   { $adapters.SetDNSServerSearchOrder($Loc3DNSSearchOrder); $number = 3 }
        'Loc4'   { $adapters.SetDNSServerSearchOrder($Loc4DNSSearchOrder); $number = 4 }
        'Loc5'   { $adapters.SetDNSServerSearchOrder($Loc5DNSSearchOrder); $number = 5 }
        default  { exit 1 }
    }

Open in new window

It's just a bit messy. If the WMI method call doesn't return anything the assignment can be moved in front of switch, but I can't remember if it does not not (most return something). For example:
$number = switch ($loc) {
        'Loc1'   { $adapters.SetDNSServerSearchOrder($Loc1DNSSearchOrder); 1}
        'Loc2'   { $adapters.SetDNSServerSearchOrder($Loc2DNSSearchOrder); 2 }
        'Loc3'   { $adapters.SetDNSServerSearchOrder($Loc3DNSSearchOrder); 3 }
        'Loc4'   { $adapters.SetDNSServerSearchOrder($Loc4DNSSearchOrder); 4 }
        'Loc5'   { $adapters.SetDNSServerSearchOrder($Loc5DNSSearchOrder); 5 }
        default  { exit 1 }
    }

Open in new window

That will be horrible if the method returns and the output was useful.
That is correct LocX is a placeholder for like Lab, Field, Web, etc.

$LabDNSSearchOrder = ("x.x.x.x")
$FieldDNSSearchOrder = ("x.x.x.x")
$WebDNSSearchOrder = ("x.x.x.x")
etc, etc

Open in new window

Then injecting whatever value you want into the switch statement is likely the best approach. It is, in essence, the "if" statement you requested, and it already knows which location is which.
So something like this?

    switch ($loc) {
        'Lab'   { $adapters.SetDNSServerSearchOrder($LabDNSSearchOrder) }
        'Field'   { $adapters.SetDNSServerSearchOrder($FieldDNSSearchOrder) }
        'Web'   { $adapters.SetDNSServerSearchOrder($WebDNSSearchOrder) }
        etc, etc,
        default  { exit 1 }
    }

    # create our trigger file
    "dns setup" > "C:\os_config\trigger\dns_$loc.txt"
}

Open in new window


If I ran the code against something at lab it would output a file called dns_lab.txt?
That will work if you're naming the file exactly after the variable. You haven't changed the value in $loc of course.

If you wanted to name it something else based on the location value you might use this pattern.
    switch ($loc) {
        'Loc1'   { $adapters.SetDNSServerSearchOrder($Loc1DNSSearchOrder); $filename = 1 }
        'Loc2'   { $adapters.SetDNSServerSearchOrder($Loc2DNSSearchOrder); $filename = 2 }
        'Loc3'   { $adapters.SetDNSServerSearchOrder($Loc3DNSSearchOrder); $filename = 3 }
        'Loc4'   { $adapters.SetDNSServerSearchOrder($Loc4DNSSearchOrder); $filename = 4 }
        'Loc5'   { $adapters.SetDNSServerSearchOrder($Loc5DNSSearchOrder); $filename = 5 }
        default  { exit 1 }
    }

Open in new window

SetDNSServerSearchOrder returns a numeric code indicating how successful it was, so we can't move the $filename assignment in front of the switch statement. However, nothing stops us including more than one statement within each of the cases.
Another way, if you cannot make a direct name part association, is to build a hash lookup table with the location name as key:
$locs = @{}
$locs['Lab'  ] = 'x.x.x.x', 'Lablocation'
$locs['Field'] = 'x.x.x.x', 'Fieldlocation'
# ...
if ($locs[$loc]) {
  $adapters.SetDNSServerSearchOrder($locs[$loc][0]) 
  "dns setup" > "C:\os_config\trigger\dns_$($locs[$loc][1])txt"
}

Open in new window

What if I just want to run the code against lab and have the output to be dns_lab.txt and the rest to be just dns.txt?

Im changing the IP addresses for LAB and I dont want this code to run against all the servers again, just the LAB servers.
In that case you might use this pattern:
   $filename = "dns.txt"

   switch ($loc) {
        'Lab'   { $adapters.SetDNSServerSearchOrder($Loc1DNSSearchOrder); $filename = 'dns_lab.txt' }
        'Loc2'   { $adapters.SetDNSServerSearchOrder($Loc2DNSSearchOrder) }
        default  { exit 1 }
    }

Open in new window

As the value is only changed in one of the switch statements everything else will use the default value.

PS the hashtable idea is a good one. If the values are hard-set rather than derived it can help a lot to keep persistent / constant configuration information out of the main body of code. A lot easier to update later if you don't have to pick through a script to figure out where everything is set.
Im not grasping the concept of the hash lookup table and where it would go.  I think I know where the $filename concept would go though.  However how would it get to the location on server I want?
echo "dns setup" > C:\os_config\trigger\*.txt

Open in new window

Extended hashtable approach integrated into an earlier snippet. As you can see I would take it a little bit further, this gives clear names to things later on rather than relying on array indexes.
$config = @{
    Lab   = @{ SearchOrder = ("x.x.x.x", "y.y.y.y"); FileName = 'dns_lab.txt' }
    Field = @{ SearchOrder = ("z.z.z.z", "a.a.a.a") }
}
$DefaultFileName = 'dns.txt'

$adapters = Get-WmiObject Win32_NetworkAdapterConfiguration -filter "IPEnabled = True and DHCPEnabled = False" | Where-Object {$_.DNSServerSearchOrder}
$win_ver=(Get-WmiObject win32_operatingsystem).version

$factloc = "C:\ProgramData\PuppetLabs\facter\facts.d\" 
if ($win_ver -lt 6) { 
        $factloc = "C:\Documents and Settings\All Users\Application Data\Puppetlabs\facter\facts.d\" 
} 

$dc_file = $factloc + 'network_location.txt' 

if (Test-Path $dc_file) {

    $net_loc = Get-Content $dc_file 
    $dc_arr = $net_loc -split "=" 
    $loc = $dc_arr[1] 

    if ($config.Contains($loc)) {
        $adapters.SetDNSServerSearchOrder($config.$loc.SearchOrder)
    } else {
        exit 1
    }

    $fileName = $DefaultFileName
    if ($config.$loc.FileName) {
        $fileName = $config.$loc.FileName
    }
    "dns setup" > "C:\os_config\trigger\$fileName"
}

Open in new window

SOLUTION
Avatar of Qlemo
Qlemo
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I appreciate both of your inputs on this matter.  so it looks like my current outline as changed quite a bit for this to work??

My code would be the following now?  I commented out my existing code but left it in there to compare.

###$Loc1DNSSearchOrder = ("1.1.1.1","1.1.1.2")
###$Loc2DNSSearchOrder = ("3.1.1.1","3.1.1.2")
###$Loc3DNSSearchOrder = ("5.1.1.1","5.1.1.2")
$config = @{
  Lab   = @{ SearchOrder = ("1.1.1.1","1.1.1.2"); FileName = 'dns_lab.txt' }
  Field = @{ SearchOrder = ("3.1.1.1","3.1.1.2") }
  Web   = @{ SearchOrder = ("5.1.1.1","5.1.1.2") }
$DefaultFileName = 'dns.txt'

$adapters = Get-WmiObject Win32_NetworkAdapterConfiguration -filter "IPEnabled = True and DHCPEnabled = False" | Where-Object {$_.DNSServerSearchOrder}
$win_ver = (Get-WmiObject win32_operatingsystem).version

#get network_location
#$fact_var = facter | findstr network_location
#$fact_var = $fact_var -split ">"
#$loc = $fact_var[1]
#$loc = $loc.trim()

$factloc = "C:\ProgramData\PuppetLabs\facter\facts.d\"
if ($win_ver -lt 6){
        $factloc = "C:\Documents and Settings\All Users\Application Data\Puppetlabs\facter\facts.d\"
}

$dc_file = $factloc + 'network_location.txt'
###$factfile = Test-Path $dc_file
###if ($factfile -eq $true) {
if (Test-Path $dc_file) {
    $net_loc = Get-Content $dc_file 
    $dc_arr = $net_loc -split "=" 
    $loc = $dc_arr[1] 

    if ($config.Contains($loc)) {
        $adapters.SetDNSServerSearchOrder($config.$loc.SearchOrder)
    } else { exit 1 }

    $fileName = $DefaultFileName
    if ($config.$loc.FileName) {
        $fileName = $config.$loc.FileName
    }
#    switch ($loc)
#        {
#            'Lab' {$adapters.SetDNSServerSearchOrder($LabDNSSearchOrder)}
#            'Lab_sub' {$adapters.SetDNSServerSearchOrder($LabDNSSearchOrder)}
#            'Lab_sub2' {exit 1}
#            'Field' {$adapters.SetDNSServerSearchOrder($FieldDNSSearchOrder)}
#            'Field_sub' {$adapters.SetDNSServerSearchOrder($FieldDNSSearchOrder)}
#            'Field_sub2' {exit 1}
#            'Web' {$adapters.SetDNSServerSearchOrder($WebDNSSearchOrder)}
#        default {exit 1}
#        }
    #create our trigger file
    echo "dns setup" > C:\os_config\trigger\$FileName
}

Open in new window

Yes, but you are missing a closing } before line 8.
Missing one closing "}" but I can't see any other problems.
###$Loc1DNSSearchOrder = ("1.1.1.1","1.1.1.2")
###$Loc2DNSSearchOrder = ("3.1.1.1","3.1.1.2")
###$Loc3DNSSearchOrder = ("5.1.1.1","5.1.1.2")
$config = @{
  Lab   = @{ SearchOrder = ("1.1.1.1","1.1.1.2"); FileName = 'dns_lab.txt' }
  Field = @{ SearchOrder = ("3.1.1.1","3.1.1.2") }
  Web   = @{ SearchOrder = ("5.1.1.1","5.1.1.2") }
}
$DefaultFileName = 'dns.txt'

$adapters = Get-WmiObject Win32_NetworkAdapterConfiguration -filter "IPEnabled = True and DHCPEnabled = False" | Where-Object {$_.DNSServerSearchOrder}
$win_ver = (Get-WmiObject win32_operatingsystem).version

#get network_location
#$fact_var = facter | findstr network_location
#$fact_var = $fact_var -split ">"
#$loc = $fact_var[1]
#$loc = $loc.trim()

$factloc = "C:\ProgramData\PuppetLabs\facter\facts.d\"
if ($win_ver -lt 6){
        $factloc = "C:\Documents and Settings\All Users\Application Data\Puppetlabs\facter\facts.d\"
}

$dc_file = $factloc + 'network_location.txt'
###$factfile = Test-Path $dc_file
###if ($factfile -eq $true) {
if (Test-Path $dc_file) {
    $net_loc = Get-Content $dc_file 
    $dc_arr = $net_loc -split "=" 
    $loc = $dc_arr[1] 

    if ($config.Contains($loc)) {
        $adapters.SetDNSServerSearchOrder($config.$loc.SearchOrder)
    } else { exit 1 }

    $fileName = $DefaultFileName
    if ($config.$loc.FileName) {
        $fileName = $config.$loc.FileName
    }
#    switch ($loc)
#        {
#            'Lab' {$adapters.SetDNSServerSearchOrder($LabDNSSearchOrder)}
#            'Lab_sub' {$adapters.SetDNSServerSearchOrder($LabDNSSearchOrder)}
#            'Lab_sub2' {exit 1}
#            'Field' {$adapters.SetDNSServerSearchOrder($FieldDNSSearchOrder)}
#            'Field_sub' {$adapters.SetDNSServerSearchOrder($FieldDNSSearchOrder)}
#            'Field_sub2' {exit 1}
#            'Web' {$adapters.SetDNSServerSearchOrder($WebDNSSearchOrder)}
#        default {exit 1}
#        }
    #create our trigger file
    echo "dns setup" > C:\os_config\trigger\$FileName
}

Open in new window

Thanks for that catch.  
Now was is interesting to me is that my $factfile statement is gone but all I was doing with that was to = it to Test-Path $dc_file and if it was true to do my switch ($loc) logic.

###$factfile = Test-Path $dc_file
###if ($factfile -eq $true) {

Open in new window



Now with this updated code all I need to do is basically add a filename at the end of the location when I want to change the IP addresses for another location and run the code. If the trigger file changes, it will run the code only on that location.

$config = @{
  Lab   = @{ SearchOrder = ("1.1.1.1","1.1.1.2"); FileName = 'dns_lab.txt' }
  Field = @{ SearchOrder = ("3.1.1.1","3.1.1.2"); FileName = 'dns_field.txt'  }
  Web   = @{ SearchOrder = ("5.1.1.1","5.1.1.2") }
}
$DefaultFileName = 'dns.txt'

Open in new window


Thanks for the excellent help!
It's quite easy to trim out variable declarations in PowerShell, doing so is a bit of a game of concise vs clear though. For example, the statements you have to fill $loc can be flattened too:
    $null, $loc = (Get-Content $dc_file -Raw) -split '='

Open in new window

Makes perfect sense to me, but it all depends on your background and experience level, sometimes shorter is not better.

When it came to the use of Test-Path I decided that declaring a variable and basing "If" on the variable was less clear than using Test-Path in the condition.
Agree, it is a clear call for Test-Path, as you do not gain anythig by using variables there. The location part however might require debugging and tests, and so it is easier to have intermediate steps - until you are certain it works, and then you can start to flatten by removing those temp vars ...
My background and experience level is not high so I would prefer a bit more code to better understand the logic that is going on here.
It took some time to complete what I started with here.  :)

Being that all these locations already have the dns.txt file in C:\os_config\trigger location. Is it possible to remove that file while it is being replaced with the new file?
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Just a thought actually, given that it's conceivable for something to move to a different $loc, that might be better as:
    if (Test-Path "C:\os_config\trigger\dns*.txt") {
        Remove-Item "C:\os_config\trigger\dns*.txt"
    }

Open in new window

WOW!  I definitely need to up my game on powershell scripting.  I know enough to get myself into trouble.  :)

Now that wont remove it from all locations, just the location that is being updated at the time?
You won't need to because your redirection method (">")  completely replaces existing content. If you were using ">>" instead you might want to, but there's no need to.
Otherwise I don't quite understand what you have and what you'd like to remove :)
Im doing this approach slowly... doing each location different times. I dont want this code to hit all locations at once -- the dns.txt file will still be in some locations.  If the file is being replaced with a different file name then it should be removed at that time.  THANKS!
So perhaps just this one then:
    if (Test-Path "C:\os_config\trigger\$DefaultFileName") {
        Remove-Item "C:\os_config\trigger\$DefaultFileName"
    }

Open in new window

It removes dns.txt if it exists, the new file will appear as normal. If the new file name already exists it will be overwritten.
I just realized something ... one section was commented out from the beginning and it was pointing to my switch ($loc) section of code.
#get network_location
#$fact_var = facter | findstr network_location
#$fact_var = $fact_var -split ">"
#$loc = $fact_var[1]
#$loc = $loc.trim()

Open in new window


Also Im not quite understanding how the switch between location takes place now by removing that section of code?  I thought I did but not absolutely sure. Is that when the hashtable comes into play?
$loc is coming from the file in $dc_file, it only fills in from there.
And... The hashtable is just a convenient place to store stuff. We use the $loc variable value to access a single "line" from that.
OK. I think I have an understanding.  Much appreciated!
Both contributors were excellent resources. Have a wealth of PowerShell knowledge.