snktech
Enthusiast
Enthusiast

PowerCLI script runs fine normally, fails when called by apcupsd (linux)

Jump to solution

So I've written a PowerCLI script to use with apcupsd to shutdown any VMs running on NAS datastores and shut them down first (so the NAS can then shut down).

Here's a cut down version of the script - ignore the variables that aren't initialised, gets pulled from a file and works fine but clutters things up so I took it out. When I run this from the command line, it works perfectly. Does exactly what I want it to do.

 

#!/usr/bin/powershell/pwsh

Write-Output "PS Environment Variables: "
Write-Output $Env:PSModulePath

$server = $($item.SERVER)
$user = $($item.USER)
$pass = ConvertTo-SecureString $($item.PASSWORD) -AsPlainText -Force

# Create credential object
$pscreds = New-Object System.Management.Automation.PSCredential ($user, $pass)

# Connect to server
Connect-VIServer $server -Credential $pscreds

# Find any datastore with NAS as part of the name, grab any running VM's and issue a guest shutdown
Get-Datastore | Where{$_.name -like '*NAS*'} | Get-VM | Where{$_.PowerState -eq 'PoweredOn'} | Shutdown-VMGuest -Confirm:$false

 

 

But when I then add it to the APCUPSD config it gets called when it's supposed to.. and fails with the following output:

 

PS Environment Variables:
/tmp/9d12ecbf-5362-4faa-98a3-d45f001a03c5/.local/share/powershell/Modules:/usr/local/share/powershell/Modules:/usr/bin/powershell/Modules

    Directory: /usr/bin/powershell/Modules

ModuleType Version    PreRelease Name                                PSEdition
---------- -------    ---------- ----                                ---------
Script     12.5.0.19…            VMware.CloudServices                Desk
<snip - lists all modules>
Script     12.1.0.16…            VMware.VumAutomation                Desk

Connect-VIServer: /root/scripts/VMShutDown/test.ps1:16
Line |
  16 |      Connect-VIServer $server -Credential $pscreds
     |      ~~~~~~~~~~~~~~~~
     | The 'Connect-VIServer' command was found in the module
     | 'VMware.VimAutomation.Core', but the module could not be
     | loaded. For more information, run 'Import-Module
     | VMware.VimAutomation.Core'.

Get-Datastore: /root/scripts/VMShutDown/test.ps1:19
Line |
  19 |      Get-Datastore | Where{$_.name -like '*NAS*'} | Get-VM | Where{$_. …
     |      ~~~~~~~~~~~~~
     | The type initializer for
     | 'VMware.VimAutomation.Sdk.Interop.V1.CoreServiceFactory' threw
     | an exception.

 

 

No difference other than it's being run by apcupsd so my thought was some kind of environment variable missing, but I specifically installed the module into the /usr/bin/powershell/Modules directory with the following, and it works just fine when called via the command line

 

Find-Module -Name 'VMware.PowerCLI' -Repository 'PSGallery' | Save-Module -Path /usr/bin/powershell/Modules
Import-Module -FullyQualifiedName '/usr/bin/powershell/Modules/VMware.PowerCLI'

 

 

So pretty stumped. Any ideas welcome.

0 Kudos
1 Solution

Accepted Solutions
snktech
Enthusiast
Enthusiast

OK... solved it!

Started just printing everything I could for debugging and saw there was no HOME var (linux var, not powershell). Apparently if PowerCLI doesn't have a HOME environment variable set, it won't work no matter where you put the modules. Added the following to the script that calls the ps1, problem solved (obviously if using a different service account would need to change accordingly).

 

 

 

export HOME=/root

 

 

 

I assume it's due to PowerCli storing its settings in ~/.local/share/VMware/PowerCLI  and not able to pick them up without a HOME var.

 

Edit: just a suggestion if anyone wants it, but if practical I'd very much recommend moving to a "check if config exists in ~ if not use the default from /etc" or similar way of doing things.

View solution in original post

7 Replies
LucD
Leadership
Leadership

Why do you hae the /tmp folder in the PSModulePath variable?
I would suggest to remove all PowerCLI related directories in all folders mentioned in PSModuePath.
Then do a fresh install with Install-Module.

Not sure why you are doing the Save-Module part?
That should only be required when installing on a station that has no connection to the PSGallery.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
snktech
Enthusiast
Enthusiast

@LucD wrote:

Why do you hae the /tmp folder in the PSModulePath variable?

That's something that only shows up when the script is called by the system, presumably it creates its own temporary space for that session in case it's needed.

The path when run as root is:

PS /root> Write-Output $Env:PSModulePath
/root/.local/share/powershell/Modules:/usr/local/share/powershell/Modules:/usr/bin/powershell/Modules

 


@LucD wrote:

Not sure why you are doing the Save-Module part?
That should only be required when installing on a station that has no connection to the PSGallery.


Initially the modules were being installed in /root/.local/share/powershell/Modules and only available to root when run from the command line (or whatever other user installed the module). When run by the system even as root the same environment variable isn't used.

Pulling the module down with Save-Module then forcing it to install to /usr/bin/powershell/Modules made it available. Prior to this I installed it as per normal with just Install-Module however the PowerCLI commands were not available at all.


@LucD wrote:

I would suggest to remove all PowerCLI related directories in all folders mentioned in PSModuePath.
Then do a fresh install with Install-Module.


Yep was how I initially had it but the module was not available to the system, hence the Save-Module. I've tried multiple fresh installs - they all work just fine when running the script directly or using the commands from a session, but they won't work when called by the system.

0 Kudos
LucD
Leadership
Leadership

If Install-Module installs in a User directory, that means the Scope is the default, namely CurrentUser.
When you do with the Scope AllUsers, it should be in a folder accessible to all users.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
snktech
Enthusiast
Enthusiast

@LucD wrote:

If Install-Module installs in a User directory, that means the Scope is the default, namely CurrentUser.
When you do with the Scope AllUsers, it should be in a folder accessible to all users.


That was one of the first things I tried to resolve the modules not being accessible, but I can't recall if I did it with a fresh powershell install or not. Will give that a try.

0 Kudos
LucD
Leadership
Leadership

Make sure to first remove the installation in all user directories.
Unfortunately Install-Module allows you to install in both scopes, without even requiring a confirmation.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
snktech
Enthusiast
Enthusiast

Still no luck. Completely removed Powershell then went through the PS Environment variables and checked every single directory to make sure there was nothing there, did a new install, then added the module with:

Install-Module -Name 'VMware.PowerCLI' -Scope AllUsers

 

Installed just fine, this time to /usr/local/share/powershell/Modules which the log of the script shows is where the module is being pulled from. But still getting the same result:

 

PS Environment Variables:
/tmp/cd37f0ff-da59-43ac-84e1-c8e2c8e4b78b/.local/share/powershell/Modules:/usr/local/share/powershell/Modules:/usr/bin/powershell/Modules

    Directory: /usr/local/share/powershell/Modules

ModuleType Version    PreRelease Name                                PSEdition
---------- -------    ---------- ----                                ---------
Script     12.5.0.19…            VMware.CloudServices                Desk
etc.

Connect-VIServer: /root/scripts/VMShutDown/test.ps1:16
Line |
  16 |      Connect-VIServer $server -Credential $pscreds
     |      ~~~~~~~~~~~~~~~~
     | The 'Connect-VIServer' command was found in the module
     | 'VMware.VimAutomation.Core', but the module could not be
     | loaded. For more information, run 'Import-Module
     | VMware.VimAutomation.Core'.

 

Only thing I can think of is to redeploy the server entirely but somewhat at a loss as to what that would achieve given powershell is just an extracted directory.

0 Kudos
snktech
Enthusiast
Enthusiast

OK... solved it!

Started just printing everything I could for debugging and saw there was no HOME var (linux var, not powershell). Apparently if PowerCLI doesn't have a HOME environment variable set, it won't work no matter where you put the modules. Added the following to the script that calls the ps1, problem solved (obviously if using a different service account would need to change accordingly).

 

 

 

export HOME=/root

 

 

 

I assume it's due to PowerCli storing its settings in ~/.local/share/VMware/PowerCLI  and not able to pick them up without a HOME var.

 

Edit: just a suggestion if anyone wants it, but if practical I'd very much recommend moving to a "check if config exists in ~ if not use the default from /etc" or similar way of doing things.